diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9f7d58a4a3cd6..a5a784027636f 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8123,7 +8123,8 @@ class Sema final { SourceLocation EllipsisLoc); bool AttachTypeConstraint(AutoTypeLoc TL, - NonTypeTemplateParmDecl *ConstrainedParameter, + NonTypeTemplateParmDecl *NewConstrainedParm, + NonTypeTemplateParmDecl *OrigConstrainedParm, SourceLocation EllipsisLoc); bool RequireStructuralType(QualType T, SourceLocation Loc); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index befc1e73c4f35..f1de491f1cd33 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1251,35 +1251,41 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, return false; } -bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, +bool Sema::AttachTypeConstraint(AutoTypeLoc TL, + NonTypeTemplateParmDecl *NewConstrainedParm, + NonTypeTemplateParmDecl *OrigConstrainedParm, SourceLocation EllipsisLoc) { - if (NTTP->getType() != TL.getType() || + if (NewConstrainedParm->getType() != TL.getType() || TL.getAutoKeyword() != AutoTypeKeyword::Auto) { - Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), + Diag(NewConstrainedParm->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), diag::err_unsupported_placeholder_constraint) - << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + << NewConstrainedParm->getTypeSourceInfo() + ->getTypeLoc() + .getSourceRange(); return true; } // FIXME: Concepts: This should be the type of the placeholder, but this is // unclear in the wording right now. DeclRefExpr *Ref = - BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation()); + BuildDeclRefExpr(OrigConstrainedParm, OrigConstrainedParm->getType(), + VK_PRValue, OrigConstrainedParm->getLocation()); if (!Ref) return true; ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), - BuildDecltypeType(Ref), NTTP->getLocation(), + BuildDecltypeType(Ref), OrigConstrainedParm->getLocation(), [&](TemplateArgumentListInfo &ConstraintArgs) { for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) ConstraintArgs.addArgument(TL.getArgLoc(I)); }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid() || - !ImmediatelyDeclaredConstraint.isUsable()) + !ImmediatelyDeclaredConstraint.isUsable()) return true; - NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); + NewConstrainedParm->setPlaceholderTypeConstraint( + ImmediatelyDeclaredConstraint.get()); return false; } @@ -1559,7 +1565,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) if (TL.isConstrained()) - if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) + if (AttachTypeConstraint(TL, Param, Param, D.getEllipsisLoc())) Invalid = true; if (Invalid) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index bf82ffb52a26e..ce461b18978c4 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3008,8 +3008,10 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc()) if (AutoLoc.isConstrained()) + // Note: We attach the uninstantiated constriant here, so that it can be + // instantiated relative to the top level, like all our other constraints. if (SemaRef.AttachTypeConstraint( - AutoLoc, Param, + AutoLoc, Param, D, IsExpandedParameterPack ? DI->getTypeLoc().getAs() .getEllipsisLoc() diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index bf5896a14991b..d28c2b22bd045 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -792,3 +792,27 @@ int foo() { return b; } } // namespace GH48182 + +namespace GH61777 { +template concept C = sizeof(T) == 4; // #61777_C +template concept C2 = sizeof(T) == sizeof(U); //#61777_C2 + +template +struct Parent { + template struct TakesUnary { static const int i = 0 ; }; // #UNARY + template auto> struct TakesBinary { static const int i = 0 ; }; //#BINARY +}; + +static_assert(Parent::TakesUnary::i == 0); +// expected-error@+3{{constraints not satisfied for class template 'TakesUnary'}} +// expected-note@#UNARY{{because 'decltype(0ULL)' (aka 'unsigned long long') does not satisfy 'C'}} +// expected-note@#61777_C{{because 'sizeof(unsigned long long) == 4' (8 == 4) evaluated to false}} +static_assert(Parent::TakesUnary::i == 0); + +static_assert(Parent::TakesBinary::i == 0); +// expected-error@+3{{constraints not satisfied for class template 'TakesBinary'}} +// expected-note@#BINARY{{because 'C2' evaluated to false}} +// expected-note@#61777_C2{{because 'sizeof(unsigned long long) == sizeof(int)' (8 == 4) evaluated to false}} +static_assert(Parent::TakesBinary::i == 0); +} +