diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3fc2839b93e50..c9187f225cad3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -288,6 +288,8 @@ Bug Fixes in This Version - 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 index a46bc758dd6af..33d6c40f157fe 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8107,6 +8107,8 @@ class Sema final { 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 index 91376cf6a34e4..450c703a27d0c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3770,6 +3770,10 @@ void Parser::ParseDeclarationSpecifiers( } 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 index e277dccb31875..d4f89cc1f0dfd 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1107,19 +1107,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { 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 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, 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 index ba1b1ea62c300..8e61349ea8768 100644 --- a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp +++ b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp @@ -47,3 +47,23 @@ void foo2(C const &a){} 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}} +}