ychen created this revision. ychen added reviewers: mizvekov, saar.raz, rsmith. Herald added subscribers: arphaman, martong, kristof.beyls. Herald added a reviewer: shafik. Herald added a project: All. ychen requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
While working on D128750 <https://reviews.llvm.org/D128750>, it is found that AutoType is not uniqued as expected in the partial ordering. This is because AutoType contains the constraints for the NTTP and the NTTP itself has a reference to the constraint in AutoType. Due to this restriction, the partial ordering between `template<C auto>` and `template<D auto>` could not be handled the same way as the partial ordering between `template<int>` and `template<int>`. By P2113 <https://reviews.llvm.org/P2113>, they should work the same way and if it doesn't, the implementation of P2113 <https://reviews.llvm.org/P2113> would be much harder if at all possible. After this patch, NTTP constraints operates the same as TTP constraints, which is to say, constraints are represented separately from the type. This is also easier to understand and maintain. Note that this patch only changes how `constrained auto` is represented in NTTP. Nothing is changed when `constrained auto` is used as function parameters, as variable declarations etc. - Add a TypeConstraint to NonTypeTemplateParmDecl in the same way as TemplateTypeParmDecl - During parsing, parse the constraint as a part of NTTP. This also means the constraint inside AutoType would be empty (and later in partial ordering, AutoType uniquing would work due to this). - Looking at how the constraint for TemplateTypeParmDecl is handled, add similar/same handling for the constraint for NonTypeTemplateParmDecl. For (TTP `W` is added for comparsion purposes.) template <typename T> concept C = true; template<C auto V, C W> struct A; AST before this patch: `-ClassTemplateDecl 0x9091c60 <line:2:1, col:32> col:32 A |-NonTypeTemplateParmDecl 0x9091818 <col:10, col:17> col:17 referenced 'C auto' depth 0 index 0 V ========> C is part of AutoType | `-ConceptSpecializationExpr 0x9091948 <col:10> 'bool' Concept 0x90916e8 'C' | `-TemplateArgument <col:17> type 'decltype(V)' | `-DecltypeType 0x90918e0 'decltype(V)' dependent | `-DeclRefExpr 0x9091878 <col:17> 'C auto' NonTypeTemplateParm 0x9091818 'V' 'C auto' |-TemplateTypeParmDecl 0x90919d0 <col:20, col:22> col:22 Concept 0x90916e8 'C' depth 0 index 1 W | `-ConceptSpecializationExpr 0x9091b08 <col:20> 'bool' Concept 0x90916e8 'C' | `-TemplateArgument <col:22> type 'W' | `-TemplateTypeParmType 0x9091aa0 'W' dependent depth 0 index 1 | `-TemplateTypeParm 0x90919d0 'W' `-CXXRecordDecl 0x9091bb0 <col:25, col:32> col:32 struct A AST after this patch: `-ClassTemplateDecl 0x887dd40 <line:2:1, col:32> col:32 A |-NonTypeTemplateParmDecl 0x887d8b8 <col:12, col:17> col:17 referenced Concept 0x887d788 'C' 'auto' depth 0 index 0 V ========> C is part of NTTP | `-ConceptSpecializationExpr 0x887da28 <col:10> 'bool' Concept 0x887d788 'C' | `-TemplateArgument <col:17> type 'decltype(V)' | `-DecltypeType 0x887d9c0 'decltype(V)' dependent | `-DeclRefExpr 0x887d960 <col:17> 'auto' NonTypeTemplateParm 0x887d8b8 'V' 'auto' |-TemplateTypeParmDecl 0x887dab0 <col:20, col:22> col:22 Concept 0x887d788 'C' depth 0 index 1 W | `-ConceptSpecializationExpr 0x887dbe8 <col:20> 'bool' Concept 0x887d788 'C' | `-TemplateArgument <col:22> type 'W' | `-TemplateTypeParmType 0x887db80 'W' dependent depth 0 index 1 | `-TemplateTypeParm 0x887dab0 'W' `-CXXRecordDecl 0x887dc90 <col:25, col:32> col:32 struct A Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D134772 Files: clang/include/clang/AST/ASTNodeTraverser.h clang/include/clang/AST/DeclTemplate.h clang/include/clang/AST/RecursiveASTVisitor.h clang/include/clang/Sema/Sema.h clang/lib/AST/ASTContext.cpp clang/lib/AST/ASTImporter.cpp clang/lib/AST/DeclPrinter.cpp clang/lib/AST/DeclTemplate.cpp clang/lib/AST/ODRHash.cpp clang/lib/AST/TextNodeDumper.cpp clang/lib/Index/IndexDecl.cpp clang/lib/Parse/ParseTemplate.cpp clang/lib/Sema/HLSLExternalSemaSource.cpp clang/lib/Sema/SemaCodeComplete.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/lib/Serialization/ASTReaderDecl.cpp clang/lib/Serialization/ASTWriterDecl.cpp clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp clang/tools/libclang/CIndex.cpp
Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -933,6 +933,11 @@ } bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + if (const auto *TC = D->getPlaceholderTypeConstraint()) { + if (VisitTypeConstraint(*TC)) + return true; + } + if (VisitDeclaratorDecl(D)) return true; @@ -5356,17 +5361,22 @@ // There is no parameter name, which makes this tricky. Try to come up // with something useful that isn't too long. - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { if (const auto *TC = TTP->getTypeConstraint()) { TC->getConceptNameInfo().printName(OS, Policy); if (TC->hasExplicitTemplateArgs()) OS << "<...>"; } else OS << (TTP->wasDeclaredWithTypename() ? "typename" : "class"); - else if (NonTypeTemplateParmDecl *NTTP = - dyn_cast<NonTypeTemplateParmDecl>(Param)) + } else if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (const auto *TC = NTTP->getPlaceholderTypeConstraint()) { + TC->getConceptNameInfo().printName(OS, Policy); + if (TC->hasExplicitTemplateArgs()) + OS << "<...>"; + } OS << NTTP->getType().getAsString(Policy); - else + } else OS << "template<...> class"; } Index: clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp =================================================================== --- clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp +++ clang/test/SemaTemplate/instantiate-expanded-type-constraint.cpp @@ -26,6 +26,12 @@ template<either<Ts, Us...>... Vs> static void foo(Vs... v); }; + + template<typename... Us> + struct R { + template<either<Ts, Us...> auto... Vs> + static void foo(); + }; }; int main() { @@ -33,4 +39,6 @@ T<int, bool>::foo(1, 2, 3); // expected-error{{no matching function for call to 'foo'}} T<int, bool>::S<char>::foo(1, 'a'); T<int, bool>::S<char>::foo('a', true); + T<int, bool>::R<char>::foo<1, 'a'>(); + T<int, bool>::R<char>::foo<'a', true>(); } Index: clang/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- clang/lib/Serialization/ASTWriterDecl.cpp +++ clang/lib/Serialization/ASTWriterDecl.cpp @@ -1708,8 +1708,8 @@ // For an expanded parameter pack, record the number of expansion types here // so that it's easier for deserialization to allocate the right amount of // memory. - Expr *TypeConstraint = D->getPlaceholderTypeConstraint(); - Record.push_back(!!TypeConstraint); + const TypeConstraint *TC = D->getPlaceholderTypeConstraint(); + Record.push_back(TC != nullptr); if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionTypes()); @@ -1717,8 +1717,15 @@ // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); - if (TypeConstraint) - Record.AddStmt(TypeConstraint); + if (TC) { + Record.AddNestedNameSpecifierLoc(TC->getNestedNameSpecifierLoc()); + Record.AddDeclarationNameInfo(TC->getConceptNameInfo()); + Record.AddDeclRef(TC->getNamedConcept()); + Record.push_back(TC->getTemplateArgsAsWritten() != nullptr); + if (TC->getTemplateArgsAsWritten()) + Record.AddASTTemplateArgumentListInfo(TC->getTemplateArgsAsWritten()); + Record.AddStmt(TC->getImmediatelyDeclaredConstraint()); + } if (D->isExpandedParameterPack()) { for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -2509,8 +2509,19 @@ // TemplateParmPosition. D->setDepth(Record.readInt()); D->setPosition(Record.readInt()); - if (D->hasPlaceholderTypeConstraint()) - D->setPlaceholderTypeConstraint(Record.readExpr()); + if (D->hasPlaceholderTypeConstraint()) { + NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc(); + DeclarationNameInfo DN = Record.readDeclarationNameInfo(); + ConceptDecl *NamedConcept = Record.readDeclAs<ConceptDecl>(); + const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; + if (Record.readBool()) + ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + Expr *ImmediatelyDeclaredConstraint = Record.readExpr(); + D->setPlaceholderTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, + NamedConcept, ArgsAsWritten, + ImmediatelyDeclaredConstraint); + } + if (D->isExpandedParameterPack()) { auto TypesAndInfos = D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>(); Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2907,23 +2907,25 @@ Param = NonTypeTemplateParmDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), - D->getPosition(), D->getIdentifier(), T, DI, ExpandedParameterPackTypes, + D->getPosition(), D->getIdentifier(), T, + D->hasPlaceholderTypeConstraint(), DI, ExpandedParameterPackTypes, ExpandedParameterPackTypesAsWritten); else Param = NonTypeTemplateParmDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), - D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); - - if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc()) - if (AutoLoc.isConstrained()) - if (SemaRef.AttachTypeConstraint( - AutoLoc, Param, - IsExpandedParameterPack - ? DI->getTypeLoc().getAs<PackExpansionTypeLoc>() - .getEllipsisLoc() - : SourceLocation())) - Invalid = true; + D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), + D->hasPlaceholderTypeConstraint(), DI); + + if (auto *TC = D->getPlaceholderTypeConstraint()) + if (SemaRef.SubstTypeConstraint(Param, TC, TemplateArgs, + IsExpandedParameterPack + ? DI->getTypeLoc() + .getAs<PackExpansionTypeLoc>() + .getEllipsisLoc() + : SourceLocation(), + EvaluateConstraints)) + return nullptr; Param->setAccess(AS_public); Param->setImplicit(D->isImplicit()); Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2423,6 +2423,36 @@ : SourceLocation()); } +bool Sema::SubstTypeConstraint( + NonTypeTemplateParmDecl *Inst, const TypeConstraint *TC, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation EllipsisLoc, bool EvaluateConstraints) { + const ASTTemplateArgumentListInfo *TemplArgInfo = + TC->getTemplateArgsAsWritten(); + + if (!EvaluateConstraints) { + Inst->setPlaceholderTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), TC->getNamedConcept(), TemplArgInfo, + TC->getImmediatelyDeclaredConstraint()); + return false; + } + + TemplateArgumentListInfo InstArgs; + + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (SubstTemplateArguments(TemplArgInfo->arguments(), TemplateArgs, + InstArgs)) + return true; + } + + return AttachTypeConstraint(TC->getNestedNameSpecifierLoc(), + TC->getConceptNameInfo(), TC->getNamedConcept(), + &InstArgs, Inst, EllipsisLoc); +} + ParmVarDecl * Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -37,6 +37,7 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" #include <iterator> using namespace clang; @@ -1109,15 +1110,17 @@ bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstr, - TemplateTypeParmDecl *ConstrainedParameter, + NamedDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { + assert(isa<TemplateTypeParmDecl>(ConstrainedParameter) || + isa<NonTypeTemplateParmDecl>(ConstrainedParameter)); return BuildTypeConstraint(SS, TypeConstr, ConstrainedParameter, EllipsisLoc, false); } bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstr, - TemplateTypeParmDecl *ConstrainedParameter, + NamedDecl *ConstrainedParameter, SourceLocation EllipsisLoc, bool AllowUnexpandedPack) { TemplateName TN = TypeConstr->Template.get(); @@ -1156,11 +1159,23 @@ } } } + + if (auto *TypeDecl = dyn_cast<TemplateTypeParmDecl>(ConstrainedParameter)) return AttachTypeConstraint( SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), ConceptName, CD, - TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, - ConstrainedParameter, EllipsisLoc); + TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, TypeDecl, + EllipsisLoc); + + if (auto *NonTypeDecl = + dyn_cast<NonTypeTemplateParmDecl>(ConstrainedParameter)) + return AttachTypeConstraint( + SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), + ConceptName, CD, + TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, NonTypeDecl, + EllipsisLoc); + + llvm_unreachable("new constrained entity?"); } template<typename ArgumentLocAppender> @@ -1251,9 +1266,15 @@ return false; } -bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, +bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, + DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, + const TemplateArgumentListInfo *TemplateArgs, + NonTypeTemplateParmDecl *NTTP, SourceLocation EllipsisLoc) { - if (NTTP->getType() != TL.getType() || + if (AutoTypeLoc TL = + NTTP->getTypeSourceInfo()->getTypeLoc().getContainedAutoTypeLoc(); + NTTP->getType() != TL.getType() || TL.getAutoKeyword() != AutoTypeKeyword::Auto) { Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_unsupported_placeholder_constraint) @@ -1266,20 +1287,32 @@ BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation()); if (!Ref) return true; + + // C++2a [temp.param]p4: + // [...] If Q is of the form C<A1, ..., An>, then let E' be + // C<T, A1, ..., An>. Otherwise, let E' be C<T>. [...] + const ASTTemplateArgumentListInfo *ArgsAsWritten = + TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs) + : nullptr; + ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( - *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), - TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + *this, NS, NameInfo, NamedConcept, + TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), + TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), BuildDecltypeType(Ref), NTTP->getLocation(), [&](TemplateArgumentListInfo &ConstraintArgs) { - for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) - ConstraintArgs.addArgument(TL.getArgLoc(I)); + if (TemplateArgs) + for (const auto &ArgLoc : TemplateArgs->arguments()) + ConstraintArgs.addArgument(ArgLoc); }, EllipsisLoc); - if (ImmediatelyDeclaredConstraint.isInvalid() || - !ImmediatelyDeclaredConstraint.isUsable()) + if (ImmediatelyDeclaredConstraint.isInvalid()) return true; - NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); + NTTP->setPlaceholderTypeConstraint(NS, NameInfo, + /*FoundDecl=*/NamedConcept, NamedConcept, + ArgsAsWritten, + ImmediatelyDeclaredConstraint.get()); return false; } @@ -1474,7 +1507,8 @@ unsigned Depth, unsigned Position, SourceLocation EqualLoc, - Expr *Default) { + Expr *Default, + bool HasTypeConstraint) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); // Check that we have valid decl-specifiers specified. @@ -1554,14 +1588,9 @@ NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create( Context, Context.getTranslationUnitDecl(), D.getBeginLoc(), D.getIdentifierLoc(), Depth, Position, ParamName, T, IsParameterPack, - TInfo); + HasTypeConstraint, TInfo); Param->setAccess(AS_public); - if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) - if (TL.isConstrained()) - if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) - Invalid = true; - if (Invalid) Param->setInvalidDecl(); @@ -7019,15 +7048,19 @@ TemplateDeductionInfo Info(DeductionArg->getExprLoc(), Param->getDepth() + 1); ParamType = QualType(); + // In template parameter list, immediately-declared constraint of the auto + // type is also an associated constraint, and will be checked along with + // the other associated constraints after checking the template argument + // list. + assert(!TSI->getTypeLoc() + .getType() + ->getContainedAutoType() + ->isConstrained() && + "the auto type should not be constrained when used in template " + "parameters"); TemplateDeductionResult Result = DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info, - /*DependentDeduction=*/true, - // We do not check constraints right now because the - // immediately-declared constraint of the auto type is - // also an associated constraint, and will be checked - // along with the other associated constraints after - // checking the template argument list. - /*IgnoreConstraints=*/true); + /*DependentDeduction=*/true); if (Result == TDK_AlreadyDiagnosed) { if (ParamType.isNull()) return ExprError(); @@ -7933,12 +7966,26 @@ : Kind), TemplateArgLoc)) return false; - } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) { + } + + if (Kind != Sema::TPL_TemplateTemplateArgumentMatch && + !isa<TemplateTemplateParmDecl>(Old)) { const Expr *NewC = nullptr, *OldC = nullptr; + + if (isa<TemplateTypeParmDecl>(New)) { if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint()) NewC = TC->getImmediatelyDeclaredConstraint(); if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint()) OldC = TC->getImmediatelyDeclaredConstraint(); + } else if (isa<NonTypeTemplateParmDecl>(New)) { + if (const auto *TC = cast<NonTypeTemplateParmDecl>(New) + ->getPlaceholderTypeConstraint()) + NewC = TC->getImmediatelyDeclaredConstraint(); + if (const auto *TC = cast<NonTypeTemplateParmDecl>(Old) + ->getPlaceholderTypeConstraint()) + OldC = TC->getImmediatelyDeclaredConstraint(); + } else + llvm_unreachable("unexpected template parameter type"); auto Diagnose = [&] { S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(), Index: clang/lib/Sema/SemaCodeComplete.cpp =================================================================== --- clang/lib/Sema/SemaCodeComplete.cpp +++ clang/lib/Sema/SemaCodeComplete.cpp @@ -3095,9 +3095,15 @@ HasDefaultArg = TTP->hasDefaultArgument(); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (const auto *TC = NTTP->getPlaceholderTypeConstraint()) { + llvm::raw_string_ostream OS(PlaceholderStr); + TC->print(OS, Policy); + OS.flush(); + } if (NTTP->getIdentifier()) - PlaceholderStr = std::string(NTTP->getIdentifier()->deuglifiedName()); + PlaceholderStr += std::string(NTTP->getIdentifier()->deuglifiedName()); NTTP->getType().getAsStringInternal(PlaceholderStr, Policy); + HasDefaultArg = NTTP->hasDefaultArgument(); } else { assert(isa<TemplateTemplateParmDecl>(*P)); Index: clang/lib/Sema/HLSLExternalSemaSource.cpp =================================================================== --- clang/lib/Sema/HLSLExternalSemaSource.cpp +++ clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -420,7 +420,7 @@ auto *SizeParam = NonTypeTemplateParmDecl::Create( AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1, &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy, - false, AST.getTrivialTypeSourceInfo(AST.IntTy)); + false, false, AST.getTrivialTypeSourceInfo(AST.IntTy)); Expr *LiteralExpr = IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4), AST.IntTy, SourceLocation()); Index: clang/lib/Parse/ParseTemplate.cpp =================================================================== --- clang/lib/Parse/ParseTemplate.cpp +++ clang/lib/Parse/ParseTemplate.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/Parse/ParseDiagnostic.h" @@ -680,7 +681,7 @@ D.setInvalidType(true); NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter( getCurScope(), D, Depth, Position, /*EqualLoc=*/SourceLocation(), - /*DefaultArg=*/nullptr); + /*DefaultArg=*/nullptr, /*HasTypeConstraint=*/false); ErrorParam->setInvalidDecl(true); SkipUntil(tok::comma, tok::greater, tok::greatergreater, StopAtSemi | StopBeforeMatch); @@ -862,8 +863,7 @@ TypeConstraint != nullptr); if (TypeConstraint) { - Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, - cast<TemplateTypeParmDecl>(NewDecl), + Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, NewDecl, EllipsisLoc); } @@ -989,8 +989,20 @@ /// template-parameter: /// ... /// parameter-declaration -NamedDecl * -Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { +NamedDecl *Parser::ParseNonTypeTemplateParameter(unsigned Depth, + unsigned Position) { + // Consume the 'type-constraint'. + CXXScopeSpec TypeConstraintSS; + TemplateIdAnnotation *TypeConstraint = nullptr; + if (isTypeConstraintAnnotation()) { + ParseOptionalCXXScopeSpecifier(TypeConstraintSS, /*ObjectType=*/nullptr, + /*ObjectHasErrors=*/false, + /*EnteringContext*/ false); + TypeConstraint = + static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + ConsumeAnnotationToken(); + } + // Parse the declaration-specifiers (i.e., the type). // FIXME: The type should probably be restricted in some way... Not all // declarators (parts of declarators?) are accepted for parameters. @@ -1038,9 +1050,16 @@ } // Create the parameter. - return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, - Depth, Position, EqualLoc, - DefaultArg.get()); + NamedDecl *NewDecl = Actions.ActOnNonTypeTemplateParameter( + getCurScope(), ParamDecl, Depth, Position, EqualLoc, DefaultArg.get(), TypeConstraint); + + if (TypeConstraint) { + // FIXME: diagnose if the constrained type is not auto. + Actions.ActOnTypeConstraint(TypeConstraintSS, TypeConstraint, NewDecl, + ParamDecl.getEllipsisLoc()); + } + + return NewDecl; } void Parser::DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc, Index: clang/lib/Index/IndexDecl.cpp =================================================================== --- clang/lib/Index/IndexDecl.cpp +++ clang/lib/Index/IndexDecl.cpp @@ -707,6 +707,9 @@ } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(TP)) { if (NTTP->hasDefaultArgument()) IndexCtx.indexBody(NTTP->getDefaultArgument(), Parent); + if (auto *C = NTTP->getPlaceholderTypeConstraint()) + IndexCtx.handleReference(C->getNamedConcept(), C->getConceptNameLoc(), + Parent, NTTP->getLexicalDeclContext()); } else if (const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(TP)) { if (TTPD->hasDefaultArgument()) handleTemplateArgumentLoc(TTPD->getDefaultArgument(), Parent, Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -2124,6 +2124,15 @@ void TextNodeDumper::VisitNonTypeTemplateParmDecl( const NonTypeTemplateParmDecl *D) { + if (const auto *TC = D->getPlaceholderTypeConstraint()) { + OS << " "; + dumpBareDeclRef(TC->getNamedConcept()); + if (TC->getNamedConcept() != TC->getFoundDecl()) { + OS << " ("; + dumpBareDeclRef(TC->getFoundDecl()); + OS << ")"; + } + } dumpType(D->getType()); OS << " depth " << D->getDepth() << " index " << D->getIndex(); if (D->isParameterPack()) Index: clang/lib/AST/ODRHash.cpp =================================================================== --- clang/lib/AST/ODRHash.cpp +++ clang/lib/AST/ODRHash.cpp @@ -399,6 +399,11 @@ } Hash.AddBoolean(D->isParameterPack()); + const TypeConstraint *TC = D->getPlaceholderTypeConstraint(); + Hash.AddBoolean(TC != nullptr); + if (TC) + AddStmt(TC->getImmediatelyDeclaredConstraint()); + Inherited::VisitNonTypeTemplateParmDecl(D); } Index: clang/lib/AST/DeclTemplate.cpp =================================================================== --- clang/lib/AST/DeclTemplate.cpp +++ clang/lib/AST/DeclTemplate.cpp @@ -190,8 +190,8 @@ if (const auto *TC = TTP->getTypeConstraint()) AC.push_back(TC->getImmediatelyDeclaredConstraint()); } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - if (const Expr *E = NTTP->getPlaceholderTypeConstraint()) - AC.push_back(E); + if (const auto *TC = NTTP->getPlaceholderTypeConstraint()) + AC.push_back(TC->getImmediatelyDeclaredConstraint()); } } if (HasRequiresClause) @@ -528,6 +528,10 @@ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { ID.AddInteger(0); ID.AddBoolean(NTTP->isParameterPack()); + ID.AddBoolean(NTTP->hasPlaceholderTypeConstraint()); + if (const TypeConstraint *TC = NTTP->getPlaceholderTypeConstraint()) + TC->getImmediatelyDeclaredConstraint()->Profile(ID, C, + /*Canonical=*/true); NTTP->getType().getCanonicalType().Profile(ID); continue; } @@ -717,10 +721,12 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl( DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, - unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - ArrayRef<QualType> ExpandedTypes, ArrayRef<TypeSourceInfo *> ExpandedTInfos) + unsigned P, IdentifierInfo *Id, QualType T, bool HasTypeConstraint, + TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes, + ArrayRef<TypeSourceInfo *> ExpandedTInfos) : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), TemplateParmPosition(D, P), ParameterPack(true), + HasTypeConstraint(HasTypeConstraint), TypeConstraintInitialized(false), ExpandedParameterPack(true), NumExpandedTypes(ExpandedTypes.size()) { if (!ExpandedTypes.empty() && !ExpandedTInfos.empty()) { auto TypesAndInfos = @@ -737,53 +743,53 @@ SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack, - TypeSourceInfo *TInfo) { - AutoType *AT = - C.getLangOpts().CPlusPlus20 ? T->getContainedAutoType() : nullptr; - return new (C, DC, - additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, - Expr *>(0, - AT && AT->isConstrained() ? 1 : 0)) + bool HasTypeConstraint, TypeSourceInfo *TInfo) { + return new ( + C, DC, + additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, + TypeConstraint>(0, HasTypeConstraint ? 1 : 0)) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, ParameterPack, - TInfo); + HasTypeConstraint, TInfo); } NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes, + QualType T, bool HasTypeConstraint, TypeSourceInfo *TInfo, + ArrayRef<QualType> ExpandedTypes, ArrayRef<TypeSourceInfo *> ExpandedTInfos) { - AutoType *AT = TInfo->getType()->getContainedAutoType(); return new (C, DC, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, - Expr *>( - ExpandedTypes.size(), AT && AT->isConstrained() ? 1 : 0)) - NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, TInfo, - ExpandedTypes, ExpandedTInfos); + TypeConstraint>(ExpandedTypes.size(), + HasTypeConstraint ? 1 : 0)) + NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, T, + HasTypeConstraint, TInfo, ExpandedTypes, + ExpandedTInfos); } NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, bool HasTypeConstraint) { - return new (C, ID, additionalSizeToAlloc<std::pair<QualType, - TypeSourceInfo *>, - Expr *>(0, - HasTypeConstraint ? 1 : 0)) - NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), - 0, 0, nullptr, QualType(), false, nullptr); + return new ( + C, ID, + additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, + TypeConstraint>(0, HasTypeConstraint ? 1 : 0)) + NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), 0, 0, + nullptr, QualType(), false, HasTypeConstraint, + nullptr); } NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned NumExpandedTypes, bool HasTypeConstraint) { - auto *NTTP = - new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, - Expr *>( - NumExpandedTypes, HasTypeConstraint ? 1 : 0)) - NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), - 0, 0, nullptr, QualType(), nullptr, None, - None); + auto *NTTP = new (C, ID, + additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, + TypeConstraint>( + NumExpandedTypes, HasTypeConstraint ? 1 : 0)) + NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(), 0, 0, + nullptr, QualType(), HasTypeConstraint, nullptr, + None, None); NTTP->NumExpandedTypes = NumExpandedTypes; return NTTP; } @@ -801,6 +807,22 @@ : SourceLocation(); } +void NonTypeTemplateParmDecl::setPlaceholderTypeConstraint( + NestedNameSpecifierLoc NNS, DeclarationNameInfo NameInfo, + NamedDecl *FoundDecl, ConceptDecl *CD, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + Expr *ImmediatelyDeclaredConstraint) { + assert(HasTypeConstraint && + "HasTypeConstraint=true must be passed at construction in order to " + "call setTypeConstraint"); + assert(!TypeConstraintInitialized && + "TypeConstraint was already initialized!"); + new (getTrailingObjects<TypeConstraint>()) + TypeConstraint(NNS, NameInfo, FoundDecl, CD, ArgsAsWritten, + ImmediatelyDeclaredConstraint); + TypeConstraintInitialized = true; +} + //===----------------------------------------------------------------------===// // TemplateTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// @@ -1422,7 +1444,8 @@ C.getTrivialTypeSourceInfo(QualType(T->getTypeForDecl(), 0)); auto *N = NonTypeTemplateParmDecl::Create( C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1, - /*Id=*/nullptr, TI->getType(), /*ParameterPack=*/true, TI); + /*Id=*/nullptr, TI->getType(), /*ParameterPack=*/true, + /*HasTypeConstraint=*/false, TI); N->setImplicit(true); // <typename T, T ...Ints> @@ -1448,7 +1471,8 @@ QualType(TemplateTypeParm->getTypeForDecl(), 0)); auto *NonTypeTemplateParm = NonTypeTemplateParmDecl::Create( C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/2, - /*Id=*/nullptr, TInfo->getType(), /*ParameterPack=*/false, TInfo); + /*Id=*/nullptr, TInfo->getType(), /*ParameterPack=*/false, + /*HasTypeConstraint=*/false, TInfo); NamedDecl *Params[] = {TemplateTemplateParm, TemplateTypeParm, NonTypeTemplateParm}; @@ -1463,7 +1487,8 @@ TypeSourceInfo *TInfo = C.getTrivialTypeSourceInfo(C.getSizeType()); auto *Index = NonTypeTemplateParmDecl::Create( C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/0, - /*Id=*/nullptr, TInfo->getType(), /*ParameterPack=*/false, TInfo); + /*Id=*/nullptr, TInfo->getType(), /*ParameterPack=*/false, + /*HasTypeConstraint=*/false, TInfo); // typename ...T auto *Ts = TemplateTypeParmDecl::Create( Index: clang/lib/AST/DeclPrinter.cpp =================================================================== --- clang/lib/AST/DeclPrinter.cpp +++ clang/lib/AST/DeclPrinter.cpp @@ -1789,6 +1789,8 @@ void DeclPrinter::VisitNonTypeTemplateParmDecl( const NonTypeTemplateParmDecl *NTTP) { + if (const TypeConstraint *TC = NTTP->getPlaceholderTypeConstraint()) + TC->print(Out, Policy); StringRef Name; if (IdentifierInfo *II = NTTP->getIdentifier()) Name = Index: clang/lib/AST/ASTImporter.cpp =================================================================== --- clang/lib/AST/ASTImporter.cpp +++ clang/lib/AST/ASTImporter.cpp @@ -5648,14 +5648,43 @@ return std::move(Err); NonTypeTemplateParmDecl *ToD = nullptr; - if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), - Importer.getToContext().getTranslationUnitDecl(), - ToInnerLocStart, ToLocation, D->getDepth(), - D->getPosition(), - ToDeclName.getAsIdentifierInfo(), ToType, - D->isParameterPack(), ToTypeSourceInfo)) + if (GetImportedOrCreateDecl( + ToD, D, Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), ToInnerLocStart, + ToLocation, D->getDepth(), D->getPosition(), + ToDeclName.getAsIdentifierInfo(), ToType, D->isParameterPack(), + D->hasPlaceholderTypeConstraint(), ToTypeSourceInfo)) return ToD; + // Import the type-constraint + if (const TypeConstraint *TC = D->getPlaceholderTypeConstraint()) { + + Error Err = Error::success(); + auto ToNNS = importChecked(Err, TC->getNestedNameSpecifierLoc()); + auto ToName = importChecked(Err, TC->getConceptNameInfo().getName()); + auto ToNameLoc = importChecked(Err, TC->getConceptNameInfo().getLoc()); + auto ToFoundDecl = importChecked(Err, TC->getFoundDecl()); + auto ToNamedConcept = importChecked(Err, TC->getNamedConcept()); + auto ToIDC = importChecked(Err, TC->getImmediatelyDeclaredConstraint()); + if (Err) + return std::move(Err); + + TemplateArgumentListInfo ToTAInfo; + const auto *ASTTemplateArgs = TC->getTemplateArgsAsWritten(); + if (ASTTemplateArgs) + if (Error Err = + ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo)) + return std::move(Err); + + ToD->setPlaceholderTypeConstraint( + ToNNS, DeclarationNameInfo(ToName, ToNameLoc), ToFoundDecl, + ToNamedConcept, + ASTTemplateArgs ? ASTTemplateArgumentListInfo::Create( + Importer.getToContext(), ToTAInfo) + : nullptr, + ToIDC); + } + if (D->hasDefaultArgument()) { ExpectedExpr ToDefaultArgOrErr = import(D->getDefaultArgument()); if (!ToDefaultArgOrErr) Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -696,6 +696,11 @@ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { ID.AddInteger(1); ID.AddBoolean(NTTP->isParameterPack()); + const TypeConstraint *TC = NTTP->getPlaceholderTypeConstraint(); + ID.AddBoolean(TC != nullptr); + if (TC) + TC->getImmediatelyDeclaredConstraint()->Profile(ID, C, + /*Canonical=*/true); ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr()); if (NTTP->isExpandedParameterPack()) { ID.AddBoolean(true); @@ -822,31 +827,29 @@ getTrivialTypeSourceInfo(ExpandedTypes.back())); } - Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), - SourceLocation(), - SourceLocation(), - NTTP->getDepth(), - NTTP->getPosition(), nullptr, - T, - TInfo, - ExpandedTypes, - ExpandedTInfos); + Param = NonTypeTemplateParmDecl::Create( + *this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(), + NTTP->getDepth(), NTTP->getPosition(), nullptr, T, + NTTP->hasPlaceholderTypeConstraint(), TInfo, ExpandedTypes, + ExpandedTInfos); } else { - Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), - SourceLocation(), - SourceLocation(), - NTTP->getDepth(), - NTTP->getPosition(), nullptr, - T, - NTTP->isParameterPack(), - TInfo); + Param = NonTypeTemplateParmDecl::Create( + *this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(), + NTTP->getDepth(), NTTP->getPosition(), nullptr, T, + NTTP->isParameterPack(), NTTP->hasPlaceholderTypeConstraint(), + TInfo); } - if (AutoType *AT = T->getContainedAutoType()) { - if (AT->isConstrained()) { - Param->setPlaceholderTypeConstraint( - canonicalizeImmediatelyDeclaredConstraint( - *this, NTTP->getPlaceholderTypeConstraint(), T)); - } + if (const auto *TC = NTTP->getPlaceholderTypeConstraint()) { + Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint( + *this, TC->getImmediatelyDeclaredConstraint(), NTTP->getType()); + Param->setPlaceholderTypeConstraint( + NestedNameSpecifierLoc(), + DeclarationNameInfo(TC->getNamedConcept()->getDeclName(), + SourceLocation()), + /*FoundDecl=*/nullptr, + // Actually canonicalizing a TemplateArgumentLoc is difficult so we + // simply omit the ArgsAsWritten + TC->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC); } CanonParams.push_back(Param); @@ -6305,7 +6308,11 @@ if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) { auto *TY = cast<NonTypeTemplateParmDecl>(Y); return TX->isParameterPack() == TY->isParameterPack() && - TX->getASTContext().hasSameType(TX->getType(), TY->getType()); + TX->getASTContext().hasSameType(TX->getType(), TY->getType()) && + TX->hasPlaceholderTypeConstraint() == + TY->hasPlaceholderTypeConstraint() && + isSameTypeConstraint(TX->getPlaceholderTypeConstraint(), + TY->getPlaceholderTypeConstraint()); } auto *TX = cast<TemplateTemplateParmDecl>(X); Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -7942,23 +7942,24 @@ bool ActOnTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, - TemplateTypeParmDecl *ConstrainedParameter, + NamedDecl *ConstrainedParameter, SourceLocation EllipsisLoc); bool BuildTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, - TemplateTypeParmDecl *ConstrainedParameter, + NamedDecl *ConstrainedParameter, SourceLocation EllipsisLoc, bool AllowUnexpandedPack); - bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); - - bool AttachTypeConstraint(AutoTypeLoc TL, - NonTypeTemplateParmDecl *ConstrainedParameter, + bool AttachTypeConstraint(NestedNameSpecifierLoc NS, + DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, + const TemplateArgumentListInfo *TemplateArgs, + NonTypeTemplateParmDecl *NTTP, SourceLocation EllipsisLoc); bool RequireStructuralType(QualType T, SourceLocation Loc); @@ -7971,7 +7972,7 @@ unsigned Depth, unsigned Position, SourceLocation EqualLoc, - Expr *DefaultArg); + Expr *DefaultArg, bool HasTypeConstraint); NamedDecl *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, @@ -9915,6 +9916,10 @@ bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC, const MultiLevelTemplateArgumentList &TemplateArgs, bool EvaluateConstraint); + bool SubstTypeConstraint(NonTypeTemplateParmDecl *Inst, + const TypeConstraint *TC, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation EllipsisLoc, bool EvaluateConstraint); bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); Index: clang/include/clang/AST/RecursiveASTVisitor.h =================================================================== --- clang/include/clang/AST/RecursiveASTVisitor.h +++ clang/include/clang/AST/RecursiveASTVisitor.h @@ -479,6 +479,7 @@ bool TraverseDeclTemplateParameterLists(T *D); bool TraverseTemplateTypeParamDeclConstraints(const TemplateTypeParmDecl *D); + bool TraverseTemplateTypeParamDeclConstraints(const NonTypeTemplateParmDecl *D); bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, unsigned Count); @@ -1925,6 +1926,14 @@ return true; } +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateTypeParamDeclConstraints( + const NonTypeTemplateParmDecl *D) { + if (const auto *TC = D->getPlaceholderTypeConstraint()) + TRY_TO(TraverseTypeConstraint(TC)); + return true; +} + DEF_TRAVERSE_DECL(TemplateTypeParmDecl, { // D is the "T" in something like "template<typename T> class vector;" if (D->getTypeForDecl()) @@ -2283,6 +2292,7 @@ DEF_TRAVERSE_DECL(ImplicitParamDecl, { TRY_TO(TraverseVarHelper(D)); }) DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, { + TRY_TO(TraverseTemplateTypeParamDeclConstraints(D)); // A non-type template parameter, e.g. "S" in template<int S> class Foo ... TRY_TO(TraverseDeclaratorHelper(D)); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) Index: clang/include/clang/AST/DeclTemplate.h =================================================================== --- clang/include/clang/AST/DeclTemplate.h +++ clang/include/clang/AST/DeclTemplate.h @@ -1415,7 +1415,7 @@ protected TemplateParmPosition, private llvm::TrailingObjects<NonTypeTemplateParmDecl, std::pair<QualType, TypeSourceInfo *>, - Expr *> { + TypeConstraint> { friend class ASTDeclReader; friend TrailingObjects; @@ -1428,12 +1428,20 @@ // down here to save memory. /// Whether this non-type template parameter is a parameter pack. - bool ParameterPack; + bool ParameterPack : 1; + + /// Whether this template type parameter has a type-constraint construct. + bool HasTypeConstraint : 1; + + /// Whether the type constraint has been initialized. This can be false if the + /// constraint was not initialized yet or if there was an error forming the + /// type constraint. + bool TypeConstraintInitialized : 1; /// Whether this non-type template parameter is an "expanded" /// parameter pack, meaning that its type is a pack expansion and we /// already know the set of types that expansion expands to. - bool ExpandedParameterPack = false; + bool ExpandedParameterPack : 1; /// The number of types in an expanded parameter pack. unsigned NumExpandedTypes = 0; @@ -1445,15 +1453,17 @@ NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, - IdentifierInfo *Id, QualType T, - bool ParameterPack, TypeSourceInfo *TInfo) + IdentifierInfo *Id, QualType T, bool ParameterPack, + bool HasTypeConstraint, TypeSourceInfo *TInfo) : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), - TemplateParmPosition(D, P), ParameterPack(ParameterPack) {} + TemplateParmPosition(D, P), ParameterPack(ParameterPack), + HasTypeConstraint(HasTypeConstraint), TypeConstraintInitialized(false), + ExpandedParameterPack(false) {} NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo, + bool HasTypeConstraint, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes, ArrayRef<TypeSourceInfo *> ExpandedTInfos); @@ -1461,12 +1471,14 @@ static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, - QualType T, bool ParameterPack, TypeSourceInfo *TInfo); + QualType T, bool ParameterPack, bool HasTypeConstraint, + TypeSourceInfo *TInfo); static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes, + QualType T, bool HasTypeConstraint, TypeSourceInfo *TInfo, + ArrayRef<QualType> ExpandedTypes, ArrayRef<TypeSourceInfo *> ExpandedTInfos); static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, @@ -1586,33 +1598,33 @@ return TypesAndInfos[I].second; } - /// Return the constraint introduced by the placeholder type of this non-type - /// template parameter (if any). - Expr *getPlaceholderTypeConstraint() const { - return hasPlaceholderTypeConstraint() ? *getTrailingObjects<Expr *>() : - nullptr; + /// Returns the type constraint associated with this template parameter (if + /// any). + const TypeConstraint *getPlaceholderTypeConstraint() const { + return TypeConstraintInitialized ? getTrailingObjects<TypeConstraint>() : + nullptr; } - void setPlaceholderTypeConstraint(Expr *E) { - *getTrailingObjects<Expr *>() = E; - } + void setPlaceholderTypeConstraint(NestedNameSpecifierLoc NNS, + DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, + ConceptDecl *CD, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + Expr *ImmediatelyDeclaredConstraint); - /// Determine whether this non-type template parameter's type has a - /// placeholder with a type-constraint. + /// Determine whether this template parameter has a type-constraint. bool hasPlaceholderTypeConstraint() const { - auto *AT = getType()->getContainedAutoType(); - return AT && AT->isConstrained(); + return HasTypeConstraint; } /// \brief Get the associated-constraints of this template parameter. - /// This will either be a vector of size 1 containing the immediately-declared - /// constraint introduced by the placeholder type, or an empty vector. + /// This will either be the immediately-introduced constraint or empty. /// - /// Use this instead of getPlaceholderImmediatelyDeclaredConstraint for - /// concepts APIs that accept an ArrayRef of constraint expressions. + /// Use this instead of getPlaceholderTypeConstraint for concepts APIs that + /// accept an ArrayRef of constraint expressions. void getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { - if (Expr *E = getPlaceholderTypeConstraint()) - AC.push_back(E); + if (HasTypeConstraint) + AC.push_back( + getPlaceholderTypeConstraint()->getImmediatelyDeclaredConstraint()); } // Implement isa/cast/dyncast/etc. Index: clang/include/clang/AST/ASTNodeTraverser.h =================================================================== --- clang/include/clang/AST/ASTNodeTraverser.h +++ clang/include/clang/AST/ASTNodeTraverser.h @@ -605,8 +605,8 @@ } void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { - if (const auto *E = D->getPlaceholderTypeConstraint()) - Visit(E); + if (const auto *TC = D->getPlaceholderTypeConstraint()) + Visit(TC->getImmediatelyDeclaredConstraint()); if (D->hasDefaultArgument()) Visit(D->getDefaultArgument(), SourceRange(), D->getDefaultArgStorage().getInheritedFrom(),
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits