diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -288,6 +288,8 @@ - Fix the assertion hit when a template consteval function appears in a nested consteval/constexpr call chain. (`#61142 `_) +- Clang now better diagnose placeholder types constrained with a concept that is + not a type concept. Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8107,6 +8107,8 @@ SourceLocation EqualLoc, ParsedType DefaultArg, bool HasTypeConstraint); + bool CheckTypeConstraint(TemplateIdAnnotation *TypeConstraint); + bool ActOnTypeConstraint(const CXXScopeSpec &SS, TemplateIdAnnotation *TypeConstraint, TemplateTypeParmDecl *ConstrainedParameter, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3770,6 +3770,10 @@ } if (!NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) goto DoneWithDeclSpec; + + if (TemplateId && !isInvalid && Actions.CheckTypeConstraint(TemplateId)) + TemplateId = nullptr; + ConsumeAnnotationToken(); SourceLocation AutoLoc = Tok.getLocation(); if (TryConsumeToken(tok::kw_decltype)) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1107,19 +1107,8 @@ return TemplateArgs; } -bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, - TemplateIdAnnotation *TypeConstr, - TemplateTypeParmDecl *ConstrainedParameter, - SourceLocation EllipsisLoc) { - return BuildTypeConstraint(SS, TypeConstr, ConstrainedParameter, EllipsisLoc, - false); -} +bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) { -bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, - TemplateIdAnnotation *TypeConstr, - TemplateTypeParmDecl *ConstrainedParameter, - SourceLocation EllipsisLoc, - bool AllowUnexpandedPack) { TemplateName TN = TypeConstr->Template.get(); ConceptDecl *CD = cast(TN.getAsTemplateDecl()); @@ -1137,9 +1126,32 @@ if (!WereArgsSpecified && CD->getTemplateParameters()->getMinRequiredArguments() > 1) { Diag(TypeConstr->TemplateNameLoc, - diag::err_type_constraint_missing_arguments) << CD; + diag::err_type_constraint_missing_arguments) + << CD; return true; } + return false; +} + +bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc) { + return BuildTypeConstraint(SS, TypeConstr, ConstrainedParameter, EllipsisLoc, + false); +} + +bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc, + bool AllowUnexpandedPack) { + + if (CheckTypeConstraint(TypeConstr)) + return true; + + TemplateName TN = TypeConstr->Template.get(); + ConceptDecl *CD = cast(TN.getAsTemplateDecl()); DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc); diff --git a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp --- a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp +++ b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp @@ -47,3 +47,23 @@ void foo3(C auto const &a){} void foo4(const C &a){} // expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}} + +namespace non_type { + template + concept C1 = true; + + auto f() -> C1 auto {} // expected-error{{concept named in type constraint is not a type concept}} + auto g(C1 auto); // expected-error{{concept named in type constraint is not a type concept}} + C1 auto a = 0; // expected-error{{concept named in type constraint is not a type concept}} + C1 decltype(auto) b = 0; // expected-error{{concept named in type constraint is not a type concept}} +} + +namespace arity { + template + concept C1 = true; + + auto f() -> C1 auto {} // expected-error{{'C1' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}} + auto g(C1 auto); // expected-error{{'C1' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}} + C1 auto a = 0; // expected-error{{'C1' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}} + C1 decltype(auto) b = 0; // expected-error{{'C1' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}} +}