Skip to content

Commit

Permalink
[Clang] Check type-constraints applied to placeholder types
Browse files Browse the repository at this point in the history
(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
  • Loading branch information
cor3ntin committed Apr 10, 2023
1 parent 26c57df commit 1cdc0e8
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 13 deletions.
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
38 changes: 25 additions & 13 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());

Expand All @@ -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);
Expand Down
20 changes: 20 additions & 0 deletions clang/test/Parser/cxx2a-placeholder-type-constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
}

0 comments on commit 1cdc0e8

Please sign in to comment.