diff options
Diffstat (limited to 'clang/lib/AST/ASTContext.cpp')
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 152 | 
1 files changed, 89 insertions, 63 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a51429264dbee..6d1db38e36ccd 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -716,6 +716,61 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,      RequiresClause->Profile(ID, C, /*Canonical=*/true);  } +static Expr * +canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC, +                                          QualType ConstrainedType) { +  // This is a bit ugly - we need to form a new immediately-declared +  // constraint that references the new parameter; this would ideally +  // require semantic analysis (e.g. template<C T> struct S {}; - the +  // converted arguments of C<T> could be an argument pack if C is +  // declared as template<typename... T> concept C = ...). +  // We don't have semantic analysis here so we dig deep into the +  // ready-made constraint expr and change the thing manually. +  ConceptSpecializationExpr *CSE; +  if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC)) +    CSE = cast<ConceptSpecializationExpr>(Fold->getLHS()); +  else +    CSE = cast<ConceptSpecializationExpr>(IDC); +  ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments(); +  SmallVector<TemplateArgument, 3> NewConverted; +  NewConverted.reserve(OldConverted.size()); +  if (OldConverted.front().getKind() == TemplateArgument::Pack) { +    // The case: +    // template<typename... T> concept C = true; +    // template<C<int> T> struct S; -> constraint is C<{T, int}> +    NewConverted.push_back(ConstrainedType); +    for (auto &Arg : OldConverted.front().pack_elements().drop_front(1)) +      NewConverted.push_back(Arg); +    TemplateArgument NewPack(NewConverted); + +    NewConverted.clear(); +    NewConverted.push_back(NewPack); +    assert(OldConverted.size() == 1 && +           "Template parameter pack should be the last parameter"); +  } else { +    assert(OldConverted.front().getKind() == TemplateArgument::Type && +           "Unexpected first argument kind for immediately-declared " +           "constraint"); +    NewConverted.push_back(ConstrainedType); +    for (auto &Arg : OldConverted.drop_front(1)) +      NewConverted.push_back(Arg); +  } +  Expr *NewIDC = ConceptSpecializationExpr::Create( +      C, NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(), +      CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(), +      CSE->getNamedConcept(), +      // Actually canonicalizing a TemplateArgumentLoc is difficult so we +      // simply omit the ArgsAsWritten +      /*ArgsAsWritten=*/nullptr, NewConverted, nullptr); + +  if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC)) +    NewIDC = new (C) CXXFoldExpr(OrigFold->getType(), SourceLocation(), NewIDC, +                                 BinaryOperatorKind::BO_LAnd, +                                 SourceLocation(), /*RHS=*/nullptr, +                                 SourceLocation(), /*NumExpansions=*/None); +  return NewIDC; +} +  TemplateTemplateParmDecl *  ASTContext::getCanonicalTemplateTemplateParmDecl(                                            TemplateTemplateParmDecl *TTP) const { @@ -743,68 +798,23 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(            TTP->isExpandedParameterPack() ?            llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);        if (const auto *TC = TTP->getTypeConstraint()) { -        // This is a bit ugly - we need to form a new immediately-declared -        // constraint that references the new parameter; this would ideally -        // require semantic analysis (e.g. template<C T> struct S {}; - the -        // converted arguments of C<T> could be an argument pack if C is -        // declared as template<typename... T> concept C = ...). -        // We don't have semantic analysis here so we dig deep into the -        // ready-made constraint expr and change the thing manually. -        Expr *IDC = TC->getImmediatelyDeclaredConstraint(); -        ConceptSpecializationExpr *CSE; -        if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC)) -          CSE = cast<ConceptSpecializationExpr>(Fold->getLHS()); -        else -          CSE = cast<ConceptSpecializationExpr>(IDC); -        ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments(); -        SmallVector<TemplateArgument, 3> NewConverted; -        NewConverted.reserve(OldConverted.size()); -          QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0); -        if (OldConverted.front().getKind() == TemplateArgument::Pack) { -          // The case: -          // template<typename... T> concept C = true; -          // template<C<int> T> struct S; -> constraint is C<{T, int}> -          NewConverted.push_back(ParamAsArgument); -          for (auto &Arg : OldConverted.front().pack_elements().drop_front(1)) -            NewConverted.push_back(Arg); -          TemplateArgument NewPack(NewConverted); - -          NewConverted.clear(); -          NewConverted.push_back(NewPack); -          assert(OldConverted.size() == 1 && -                 "Template parameter pack should be the last parameter"); -        } else { -          assert(OldConverted.front().getKind() == TemplateArgument::Type && -                 "Unexpected first argument kind for immediately-declared " -                 "constraint"); -          NewConverted.push_back(ParamAsArgument); -          for (auto &Arg : OldConverted.drop_front(1)) -            NewConverted.push_back(Arg); -        } -        Expr *NewIDC = ConceptSpecializationExpr::Create(*this, -            NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(), -            CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(), -            CSE->getNamedConcept(), -            // Actually canonicalizing a TemplateArgumentLoc is difficult so we -            // simply omit the ArgsAsWritten -            /*ArgsAsWritten=*/nullptr, NewConverted, nullptr); - -        if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC)) -          NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(), -                                           SourceLocation(), NewIDC, -                                           BinaryOperatorKind::BO_LAnd, -                                           SourceLocation(), /*RHS=*/nullptr, -                                           SourceLocation(), -                                           /*NumExpansions=*/None); - +        Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint( +                *this, TC->getImmediatelyDeclaredConstraint(), +                ParamAsArgument); +        TemplateArgumentListInfo CanonArgsAsWritten; +        if (auto *Args = TC->getTemplateArgsAsWritten()) +          for (const auto &ArgLoc : Args->arguments()) +            CanonArgsAsWritten.addArgument( +                TemplateArgumentLoc(ArgLoc.getArgument(), +                                    TemplateArgumentLocInfo()));          NewTTP->setTypeConstraint(              NestedNameSpecifierLoc(),              DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),                                  SourceLocation()), /*FoundDecl=*/nullptr,              // Actually canonicalizing a TemplateArgumentLoc is difficult so we              // simply omit the ArgsAsWritten -            CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC); +            TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC);        }        CanonParams.push_back(NewTTP);      } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { @@ -839,6 +849,13 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(                                                  NTTP->isParameterPack(),                                                  TInfo);        } +      if (AutoType *AT = T->getContainedAutoType()) { +        if (AT->isConstrained()) { +          Param->setPlaceholderTypeConstraint( +              canonicalizeImmediatelyDeclaredConstraint( +                  *this, NTTP->getPlaceholderTypeConstraint(), T)); +        } +      }        CanonParams.push_back(Param);      } else @@ -943,7 +960,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,                         Builtin::Context &builtins)      : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()),        TemplateSpecializationTypes(this_()), -      DependentTemplateSpecializationTypes(this_()), +      DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()),        SubstTemplateTemplateParmPacks(this_()),        CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),        SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), @@ -5124,21 +5141,29 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType,  /// getAutoType - Return the uniqued reference to the 'auto' type which has been  /// deduced to the given type, or to the canonical undeduced 'auto' type, or the  /// canonical deduced-but-dependent 'auto' type. -QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, -                                 bool IsDependent, bool IsPack) const { +QualType +ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, +                        bool IsDependent, bool IsPack, +                        ConceptDecl *TypeConstraintConcept, +                        ArrayRef<TemplateArgument> TypeConstraintArgs) const {    assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); -  if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) +  if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && +      !TypeConstraintConcept && !IsDependent)      return getAutoDeductType();    // Look in the folding set for an existing type.    void *InsertPos = nullptr;    llvm::FoldingSetNodeID ID; -  AutoType::Profile(ID, DeducedType, Keyword, IsDependent, IsPack); +  AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent, +                    TypeConstraintConcept, TypeConstraintArgs);    if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos))      return QualType(AT, 0); -  auto *AT = new (*this, TypeAlignment) -      AutoType(DeducedType, Keyword, IsDependent, IsPack); +  void *Mem = Allocate(sizeof(AutoType) + +                       sizeof(TemplateArgument) * TypeConstraintArgs.size(), +                       TypeAlignment); +  auto *AT = new (Mem) AutoType(DeducedType, Keyword, IsDependent, IsPack, +                                TypeConstraintConcept, TypeConstraintArgs);    Types.push_back(AT);    if (InsertPos)      AutoTypes.InsertNode(AT, InsertPos); @@ -5200,7 +5225,8 @@ QualType ASTContext::getAutoDeductType() const {    if (AutoDeductTy.isNull())      AutoDeductTy = QualType(        new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, -                                          /*dependent*/false, /*pack*/false), +                                          /*dependent*/false, /*pack*/false, +                                          /*concept*/nullptr, /*args*/{}),        0);    return AutoDeductTy;  }  | 
