[Clang] Check type-constraints applied to placeholder types

(and deduced return types)

Previously, only type constraints applied to type parameter
were semantically checked.

A diagnostic would still be emitted on instantiation, but it was
too late, lacked clarity, and was inconsistent with type parameters.

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D147925
This commit is contained in:
Corentin Jabot 2023-04-10 11:52:30 +02:00
parent 26c57df8aa
commit 1cdc0e83c8
5 changed files with 53 additions and 13 deletions

View File

@ -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 <https://github.com/llvm/llvm-project/issues/61142>`_)
- Clang now better diagnose placeholder types constrained with a concept that is
not a type concept.
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@ -8107,6 +8107,8 @@ public:
SourceLocation EqualLoc,
ParsedType DefaultArg, bool HasTypeConstraint);
bool CheckTypeConstraint(TemplateIdAnnotation *TypeConstraint);
bool ActOnTypeConstraint(const CXXScopeSpec &SS,
TemplateIdAnnotation *TypeConstraint,
TemplateTypeParmDecl *ConstrainedParameter,

View File

@ -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)) {

View File

@ -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<ConceptDecl>(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<ConceptDecl>(TN.getAsTemplateDecl());
DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name),
TypeConstr->TemplateNameLoc);

View File

@ -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<int v>
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<typename v, typename>
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}}
}