Commit e03ead67 authored by Saar Raz's avatar Saar Raz
Browse files

[Concepts] Placeholder constraints and abbreviated templates

This patch implements P1141R2 "Yet another approach for constrained declarations".

General strategy for this patch was:

- Expand AutoType to include optional type-constraint, reflecting the wording and easing the integration of constraints.
- Replace autos in parameter type specifiers with invented parameters in GetTypeSpecTypeForDeclarator, using the same logic
  previously used for generic lambdas, now unified with abbreviated templates, by:
  - Tracking the template parameter lists in the Declarator object
  - Tracking the template parameter depth before parsing function declarators (at which point we can match template
    parameters against scope specifiers to know if we have an explicit template parameter list to append invented parameters
    to or not).
- When encountering an AutoType in a parameter context we check a stack of InventedTemplateParameterInfo structures that
  contain the info required to create and accumulate invented template parameters (fields that were already present in
  LambdaScopeInfo, which now inherits from this class and is looked up when an auto is encountered in a lambda context).

Differential Revision: https://reviews.llvm.org/D65042
parent 6e73fee7
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ class AtomicExpr;
class BlockExpr;
class BuiltinTemplateDecl;
class CharUnits;
class ConceptDecl;
class CXXABI;
class CXXConstructorDecl;
class CXXMethodDecl;
@@ -211,7 +212,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
  mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
  mutable llvm::FoldingSet<DependentUnaryTransformType>
    DependentUnaryTransformTypes;
  mutable llvm::FoldingSet<AutoType> AutoTypes;
  mutable llvm::ContextualFoldingSet<AutoType, ASTContext&> AutoTypes;
  mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
    DeducedTemplateSpecializationTypes;
  mutable llvm::FoldingSet<AtomicType> AtomicTypes;
@@ -1542,7 +1543,9 @@ public:

  /// C++11 deduced auto type.
  QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
                       bool IsDependent, bool IsPack = false) const;
                       bool IsDependent, bool IsPack = false,
                       ConceptDecl *TypeConstraintConcept = nullptr,
                       ArrayRef<TemplateArgument> TypeConstraintArgs ={}) const;

  /// C++11 deduction pattern for 'auto' type.
  QualType getAutoDeductType() const;
+2 −2
Original line number Diff line number Diff line
@@ -548,8 +548,8 @@ public:
  }

  void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
    if (const auto *TC = D->getPlaceholderTypeConstraint())
      Visit(TC->getImmediatelyDeclaredConstraint());
    if (const auto *E = D->getPlaceholderTypeConstraint())
      Visit(E);
    if (D->hasDefaultArgument())
      Visit(D->getDefaultArgument(), SourceRange(),
            D->getDefaultArgStorage().getInheritedFrom(),
+29 −14
Original line number Diff line number Diff line
@@ -1102,6 +1102,17 @@ public:
  /// template.
  ArrayRef<TemplateArgument> getInjectedTemplateArgs();

  /// Return whether this function template is an abbreviated function template,
  /// e.g. `void foo(auto x)` or `template<typename T> void foo(auto x)`
  bool isAbbreviated() const {
    // Since the invented template parameters generated from 'auto' parameters
    // are either appended to the end of the explicit template parameter list or
    // form a new template paramter list, we can simply observe the last
    // parameter to determine if such a thing happened.
    const TemplateParameterList *TPL = getTemplateParameters();
    return TPL->getParam(TPL->size() - 1)->isImplicit();
  }

  /// Merge \p Prev with our RedeclarableTemplateDecl::Common.
  void mergePrevDecl(FunctionTemplateDecl *Prev);

@@ -1215,7 +1226,6 @@ public:
                                      bool ParameterPack,
                                      bool HasTypeConstraint = false,
                                      Optional<unsigned> NumExpanded = None);

  static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
                                                  unsigned ID);
  static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
@@ -1374,7 +1384,8 @@ class NonTypeTemplateParmDecl final
    : public DeclaratorDecl,
      protected TemplateParmPosition,
      private llvm::TrailingObjects<NonTypeTemplateParmDecl,
                                    std::pair<QualType, TypeSourceInfo *>> {
                                    std::pair<QualType, TypeSourceInfo *>,
                                    Expr *> {
  friend class ASTDeclReader;
  friend TrailingObjects;

@@ -1429,10 +1440,12 @@ public:
         ArrayRef<TypeSourceInfo *> ExpandedTInfos);

  static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
                                                     unsigned ID);
                                                     unsigned ID,
                                                     bool HasTypeConstraint);
  static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
                                                     unsigned ID,
                                                     unsigned NumExpandedTypes);
                                                     unsigned NumExpandedTypes,
                                                     bool HasTypeConstraint);

  using TemplateParmPosition::getDepth;
  using TemplateParmPosition::setDepth;
@@ -1543,20 +1556,22 @@ public:
    return TypesAndInfos[I].second;
  }

  /// Return the type-constraint in the placeholder type of this non-type
  /// Return the constraint introduced by the placeholder type of this non-type
  /// template parameter (if any).
  TypeConstraint *getPlaceholderTypeConstraint() const {
    // TODO: Concepts: Implement once we have actual placeholders with type
    //                 constraints.
    return nullptr;
  Expr *getPlaceholderTypeConstraint() const {
    return hasPlaceholderTypeConstraint() ? *getTrailingObjects<Expr *>() :
        nullptr;
  }

  void setPlaceholderTypeConstraint(Expr *E) {
    *getTrailingObjects<Expr *>() = E;
  }

  /// Determine whether this non-type template parameter's type has a
  /// placeholder with a type-constraint.
  bool hasPlaceholderTypeConstraint() const {
    // TODO: Concepts: Implement once we have actual placeholders with type
    //                 constraints.
    return false;
    auto *AT = getType()->getContainedAutoType();
    return AT && AT->isConstrained();
  }

  /// \brief Get the associated-constraints of this template parameter.
@@ -1566,8 +1581,8 @@ public:
  /// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for
  /// concepts APIs that accept an ArrayRef of constraint expressions.
  void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const {
    if (TypeConstraint *TC = getPlaceholderTypeConstraint())
      AC.push_back(TC->getImmediatelyDeclaredConstraint());
    if (Expr *E = getPlaceholderTypeConstraint())
      AC.push_back(E);
  }

  // Implement isa/cast/dyncast/etc.
+2 −0
Original line number Diff line number Diff line
@@ -99,6 +99,8 @@ def DeclRef : RefPropertyType<"Decl"> { let ConstWhenWriting = 1; }
    SubclassPropertyType<"TagDecl", DeclRef>;
  def TemplateDeclRef :
    SubclassPropertyType<"TemplateDecl", DeclRef>;
  def ConceptDeclRef :
    SubclassPropertyType<"ConceptDecl", DeclRef>;
  def TemplateTypeParmDeclRef :
    SubclassPropertyType<"TemplateTypeParmDecl", DeclRef>;
  def TemplateTemplateParmDeclRef :
+13 −1
Original line number Diff line number Diff line
@@ -1040,7 +1040,13 @@ DEF_TRAVERSE_TYPE(UnaryTransformType, {
  TRY_TO(TraverseType(T->getUnderlyingType()));
})

DEF_TRAVERSE_TYPE(AutoType, { TRY_TO(TraverseType(T->getDeducedType())); })
DEF_TRAVERSE_TYPE(AutoType, {
  TRY_TO(TraverseType(T->getDeducedType()));
  if (T->isConstrained()) {
    TRY_TO(TraverseDecl(T->getTypeConstraintConcept()));
    TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs()));
  }
})
DEF_TRAVERSE_TYPE(DeducedTemplateSpecializationType, {
  TRY_TO(TraverseTemplateName(T->getTemplateName()));
  TRY_TO(TraverseType(T->getDeducedType()));
@@ -1287,6 +1293,12 @@ DEF_TRAVERSE_TYPELOC(UnaryTransformType, {

DEF_TRAVERSE_TYPELOC(AutoType, {
  TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
  if (TL.isConstrained()) {
    TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()));
    TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo()));
    for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
      TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
  }
})

DEF_TRAVERSE_TYPELOC(DeducedTemplateSpecializationType, {
Loading