saar.raz updated this revision to Diff 159378.
saar.raz added a comment.
Split TryParseConstrainedParameter and ParseConstrainedTemplateParameter in
preparation for requries expressions.
Repository:
rC Clang
https://reviews.llvm.org/D44352
Files:
include/clang/AST/DeclTemplate.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/TemplateBase.h
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/AST/ASTDumper.cpp
lib/AST/ASTImporter.cpp
lib/AST/DeclTemplate.cpp
lib/AST/ODRHash.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseTemplate.cpp
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaConcept.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterDecl.cpp
test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
test/CXX/concepts-ts/temp/temp.param/p10.cpp
test/Parser/cxx-constrained-template-param-with-partial-id.cpp
test/Parser/cxx-constrained-template-param.cpp
tools/libclang/CIndex.cpp
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -750,6 +750,10 @@
}
bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ if (Expr *CE = D->getConstraintExpression())
+ if (Visit(MakeCXCursor(CE, StmtParent, TU, RegionOfInterest)))
+ return true;
+
// Visit the default argument.
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
if (TypeSourceInfo *DefArg = D->getDefaultArgumentInfo())
@@ -898,6 +902,10 @@
bool CursorVisitor::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
if (VisitDeclaratorDecl(D))
return true;
+
+ if (Expr *CE = D->getConstraintExpression())
+ if (Visit(MakeCXCursor(CE, StmtParent, TU, RegionOfInterest)))
+ return true;
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
if (Expr *DefArg = D->getDefaultArgument())
@@ -929,7 +937,11 @@
bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
if (VisitTemplateParameters(D->getTemplateParameters()))
return true;
-
+
+ if (Expr *CE = D->getConstraintExpression())
+ if (Visit(MakeCXCursor(CE, StmtParent, TU, RegionOfInterest)))
+ return true;
+
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited() &&
VisitTemplateArgumentLoc(D->getDefaultArgument()))
return true;
Index: test/Parser/cxx-constrained-template-param.cpp
===================================================================
--- /dev/null
+++ test/Parser/cxx-constrained-template-param.cpp
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
+// expected-no-diagnostics
+
+namespace type
+{
+ template<typename T>
+ concept C1 = true;
+
+ template<C1 T, C1 U = int>
+ using A = T[10];
+
+ using a = A<int>;
+
+ namespace ns {
+ template<typename T, int a = 0>
+ concept C2 = true;
+ }
+
+ template<ns::C2 T1, ::type::ns::C2 T2> requires sizeof(T1) <= sizeof(T2)
+ struct B { };
+
+ using b = B<int, int>;
+
+ template<ns::C2... T1>
+ struct C { };
+
+ using c1 = C<char, char, char>;
+ using c2 = C<char, char, char, char>;
+}
+
+namespace non_type
+{
+ template<int v>
+ concept C1 = true;
+
+ template<C1 v, C1 u = 0>
+ int A = v;
+
+ int& a = A<1>;
+
+ namespace ns {
+ template<bool x, typename T = int>
+ concept C2 = true;
+ }
+
+ template<ns::C2 v1, ::non_type::ns::C2 v2> requires sizeof(v1) <= sizeof(v2)
+ struct B { };
+
+ using b = B<true, false>;
+
+ template<ns::C2... T1>
+ struct C { };
+
+ using c1 = C<false, true, false>;
+ using c2 = C<false, true, false, false>;
+}
+
+namespace temp
+{
+ template<typename>
+ struct test1 { };
+
+ template<typename>
+ struct test2 { };
+
+ template<template<typename> typename T>
+ concept C1 = true;
+
+ template<C1 TT, C1 UU = test1>
+ using A = TT<int>;
+
+ using a = A<test1>;
+
+ namespace ns {
+ template<template<typename> typename... TT>
+ concept C2 = true;
+ }
+
+ template<ns::C2 TT1, ::temp::ns::C2 TT2>
+ requires sizeof(TT1<int>) <= sizeof(TT2<int>)
+ struct B { };
+
+ using b = B<test1, test2>;
+
+ template<ns::C2... T1>
+ struct C { };
+
+ using c1 = C<test1>;
+ using c2 = C<test1, test2, test2>;
+}
\ No newline at end of file
Index: test/Parser/cxx-constrained-template-param-with-partial-id.cpp
===================================================================
--- /dev/null
+++ test/Parser/cxx-constrained-template-param-with-partial-id.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ %s -verify
+
+template<typename T, int a>
+concept C1 = true;
+
+template<C1 T> // expected-error {{concept 'C1' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}} expected-error{{explicit specialization of alias templates is not permitted}}
+using badA = T[10];
+
+template<C1<0> T>
+using A = T[10];
+
+using a = A<int>;
+
+namespace ns {
+ template<typename T, typename U, typename... X>
+ concept C2 = true;
+}
+
+template<ns::C2 T1, ::ns::C2 T2> // expected-error 2{{concept 'C2' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}}
+requires sizeof(T1) <= sizeof(T2) // expected-error{{expected unqualified-id}}
+struct badB { };
+
+template<ns::C2<int> T1, ::ns::C2<char, T1> T2>
+ requires sizeof(T1) <= sizeof(T2)
+struct B { };
+
+using b = B<int, int>;
+
+template<ns::C2... T1> // expected-error {{concept 'C2' requires more than 1 template argument; provide the remaining arguments explicitly to use it here}} expected-error{{extraneous 'template<>' in declaration of struct 'badC'}}
+struct badC { };
+
+template<ns::C2<int>... T1>
+struct C { };
+
+using c1 = C<char, char, char>;
+using c2 = C<char, char, char, char>;
\ No newline at end of file
Index: test/CXX/concepts-ts/temp/temp.param/p10.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.param/p10.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T>
+concept C1 = sizeof(T) == 1; // expected-note 2{{because 'sizeof(short) == 1' (2 == 1) evaluated to false}} expected-note {{because 'sizeof(int) == 1' (4 == 1) evaluated to false}}
+
+template<C1 T> // expected-note {{because 'int' does not satisfy 'C1'}}
+using A = T;
+
+using a1 = A<int>; // expected-error {{constraints not satisfied for alias template 'A' [with T = int]}}
+using a2 = A<char>;
+
+template<typename T>
+concept C2 = sizeof(T) == 2; // expected-note 2{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
+
+template<C1 T1, C2 T2> // expected-note 2{{because 'short' does not satisfy 'C1'}} expected-note {{because 'char' does not satisfy 'C2'}} expected-note {{and 'char' does not satisfy 'C2'}}
+using B = T1;
+
+using b1 = B<char, short>;
+using b2 = B<char, char>; // expected-error {{constraints not satisfied for alias template 'B' [with T1 = char, T2 = char]}}
+using b3 = B<short, short>; // expected-error {{constraints not satisfied for alias template 'B' [with T1 = short, T2 = short]}}
+using b4 = B<short, char>; // expected-error {{constraints not satisfied for alias template 'B' [with T1 = short, T2 = char]}}
+
+template<typename... T>
+concept C3 = (sizeof(T) + ...) == 12; // expected-note {{because 'sizeof(char [11]) == 12' (11 == 12) evaluated to false}} expected-note {{because 'sizeof(char [10]) == 12' (10 == 12) evaluated to false}} expected-note {{because 'sizeof(char [12]) + sizeof(int [3]) + sizeof(short [6]) == 12' (36 == 12) evaluated to false}}
+
+template<C3 T1, C3 T2, C3 T3> // expected-note {{because 'char [11]' does not satisfy 'C3'}} expected-note {{and 'char [10]' does not satisfy 'C3'}}
+using C = T2;
+
+using c1 = C<char[12], int[3], short[6]>;
+using c2 = C<char[12], char[11], char[10]>; // expected-error {{constraints not satisfied for alias template 'C' [with T1 = char [12], T2 = char [11], T3 = char [10]]}}
+
+template<C3... Ts> // expected-note {{because 'C3<char [12], int [3], short [6]>' evaluated to false}}
+using D = int;
+
+using d1 = D<char[12], int[3], short[6]>; // expected-error {{constraints not satisfied for alias template 'D' [with Ts = <char [12], int [3], short [6]>}}
+using d2 = D<int, int, int>;
+using d3 = D<short, short, short, short, short, short>;
+
+template<typename T>
+concept C4 = sizeof(T) == 4; // expected-note 3{{because 'sizeof(char) == 4' (1 == 4) evaluated to false}}
+
+template<C4... Ts> // expected-note 2{{because 'char' does not satisfy 'C4'}} expected-note {{and 'char' does not satisfy 'C4'}}
+using E = int;
+
+using e1 = E<int>;
+using e2 = E<char, int>; // expected-error {{constraints not satisfied for alias template 'E' [with Ts = <char, int>]}}
+using e3 = E<char, char>; // expected-error {{constraints not satisfied for alias template 'E' [with Ts = <char, char>]}}
+using e4 = E<>;
+
+template<typename T, typename U>
+constexpr bool is_same_v = false;
+
+template<typename T>
+constexpr bool is_same_v<T, T> = true;
+
+template<typename T, typename U>
+concept Same = is_same_v<T, U>; // expected-note {{because 'is_same_v<long, int>' evaluated to false}}
+
+template<Same<int> T> // expected-note {{because 'Same<long, int>' evaluated to false}}
+using F = T;
+
+using f1 = F<int>;
+using f2 = F<long>; // expected-error {{constraints not satisfied for alias template 'F' [with T = long]}}
+
+template<typename T, typename... Ts>
+concept OneOf = (is_same_v<T, Ts> || ...); // expected-note 2{{because 'is_same_v<char, char [1]>' evaluated to false}} expected-note 2{{and 'is_same_v<char, char [2]>' evaluated to false}} expected-note 2{{because 'is_same_v<short, int>' evaluated to false}} expected-note 2{{and 'is_same_v<short, long>' evaluated to false}} expected-note 2{{and 'is_same_v<short, char>' evaluated to false}}
+
+template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U> // expected-note 2{{because 'OneOf<char, char [1], char [2]>' evaluated to false}} expected-note {{because 'OneOf<short, int, long, char>' evaluated to false}} expected-note {{and 'OneOf<short, int, long, char>' evaluated to false}}
+using G = T;
+
+using g1 = G<char[1], int>;
+using g2 = G<char, int>; // expected-error{{constraints not satisfied for alias template 'G' [with T = char, U = int]}}
+using g3 = G<char[1], short>; // expected-error{{constraints not satisfied for alias template 'G' [with T = char [1], U = short]}}
+using g4 = G<char, short>; // expected-error{{constraints not satisfied for alias template 'G' [with T = char, U = short]}}
+
+template<OneOf<char[1], char[2]>... Ts>
+using H = int;
+
+using h1 = H<char[1], int>;
+using h2 = H<int, int>;
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
===================================================================
--- test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.decl/class-template-decl.cpp
@@ -7,6 +7,14 @@
template <typename U> requires bool(U())
struct A;
+template<typename T>
+concept C1 = true;
+
+template <C1 T> requires bool(T())
+struct B;
+template <C1 U> requires bool(U())
+struct B;
+
} // end namespace nodiag
namespace diag {
@@ -24,6 +32,14 @@
template <typename T> requires !0 // expected-error{{associated constraints differ in template redeclaration}}
struct C;
+template<typename T>
+concept C1 = true;
+
+template <C1 T> // expected-note{{previous template declaration is here}}
+struct D;
+template <typename T> requires C1<T> // expected-error{{associated constraints differ in template redeclaration}}
+struct D;
+
} // end namespace diag
namespace nodiag {
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -1567,6 +1567,11 @@
Record.push_back(D->wasDeclaredWithTypename());
+ Expr *CE = D->getConstraintExpression();
+ Record.push_back(CE != nullptr);
+ if (CE)
+ Record.AddStmt(CE);
+
bool OwnsDefaultArg = D->hasDefaultArgument() &&
!D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg);
@@ -1598,6 +1603,10 @@
} else {
// Rest of NonTypeTemplateParmDecl.
Record.push_back(D->isParameterPack());
+ Expr *CE = D->getConstraintExpression();
+ Record.push_back(CE != nullptr);
+ if (CE)
+ Record.AddStmt(CE);
bool OwnsDefaultArg = D->hasDefaultArgument() &&
!D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg);
@@ -1627,6 +1636,10 @@
} else {
// Rest of TemplateTemplateParmDecl.
Record.push_back(D->isParameterPack());
+ Expr *CE = D->getConstraintExpression();
+ Record.push_back(CE != nullptr);
+ if (CE)
+ Record.AddStmt(CE);
bool OwnsDefaultArg = D->hasDefaultArgument() &&
!D->defaultArgumentWasInherited();
Record.push_back(OwnsDefaultArg);
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -5853,7 +5853,7 @@
Record->push_back(TemplateParams->size());
for (const auto &P : *TemplateParams)
- AddDeclRef(P); // TODO: Concepts - constrained parameters.
+ AddDeclRef(P);
if (const Expr *RequiresClause = TemplateParams->getRequiresClause()) {
Record->push_back(true);
AddStmt(const_cast<Expr*>(RequiresClause));
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -2287,6 +2287,9 @@
D->setDeclaredWithTypename(Record.readInt());
+ if (Record.readInt())
+ D->setConstraintExpression(Record.readExpr());
+
if (Record.readInt())
D->setDefaultArgument(GetTypeSourceInfo());
}
@@ -2306,6 +2309,8 @@
} else {
// Rest of NonTypeTemplateParmDecl.
D->ParameterPack = Record.readInt();
+ if (Record.readInt())
+ D->setConstraintExpression(Record.readExpr());
if (Record.readInt())
D->setDefaultArgument(Record.readExpr());
}
@@ -2325,6 +2330,8 @@
} else {
// Rest of TemplateTemplateParmDecl.
D->ParameterPack = Record.readInt();
+ if (Record.readInt())
+ D->setConstraintExpression(Record.readExpr());
if (Record.readInt())
D->setDefaultArgument(Reader.getContext(),
Record.readTemplateArgumentLoc());
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -8664,7 +8664,6 @@
Params.reserve(NumParams);
while (NumParams--)
Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx));
- // TODO: Concepts: Constrained parameters
bool HasRequiresClause = Record[Idx++];
Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr;
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2181,7 +2181,12 @@
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(),
D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack());
Inst->setAccess(AS_public);
-
+ if (Expr *CE = D->getConstraintExpression()) {
+ ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs);
+ if (Result.isInvalid())
+ return nullptr;
+ Inst->setConstraintExpression(Result.get());
+ }
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
TypeSourceInfo *InstantiatedDefaultArg =
SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs,
@@ -2330,6 +2335,12 @@
if (Invalid)
Param->setInvalidDecl();
+ if (Expr *CE = D->getConstraintExpression()) {
+ ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs);
+ if (Result.isInvalid())
+ return nullptr;
+ Param->setConstraintExpression(Result.get());
+ }
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
EnterExpressionEvaluationContext ConstantEvaluated(
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated);
@@ -2454,6 +2465,12 @@
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams);
+ if (Expr *CE = D->getConstraintExpression()) {
+ ExprResult Result = SemaRef.SubstExpr(CE, TemplateArgs);
+ if (Result.isInvalid())
+ return nullptr;
+ Param->setConstraintExpression(Result.get());
+ }
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
D->getDefaultArgument().getTemplateQualifierLoc();
@@ -3262,10 +3279,7 @@
void *InsertPos = nullptr;
ClassTemplateSpecializationDecl *PrevDecl
= ClassTemplate->findPartialSpecialization(Converted,
- // TODO: Concepts - change this
- // to associated constraints once
- // we have them.
- InstParams->getRequiresClause(),
+ InstParams->getAssociatedConstraints(),
InsertPos);
// Build the canonical type that describes the converted template
@@ -3398,10 +3412,7 @@
void *InsertPos = nullptr;
VarTemplateSpecializationDecl *PrevDecl =
VarTemplate->findPartialSpecialization(Converted,
- // TODO: Concepts - change this
- // to associated constraints once
- // we have them.
- InstParams->getRequiresClause(),
+ InstParams->getAssociatedConstraints(),
InsertPos);
// Build the canonical type that describes the converted template
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -4431,7 +4431,7 @@
QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0);
NamedDecl *TemplParamPtr = TemplParam;
FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt(
- Loc, Loc, TemplParamPtr, Loc, nullptr);
+ Context, Loc, Loc, TemplParamPtr, Loc, nullptr, nullptr);
QualType FuncParam =
SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false)
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -904,15 +904,20 @@
return QualType();
}
-Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S,
+ const DeclSpec &DS,
+ SourceLocation StartLoc,
+ TypeSourceInfo *TInfo,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ bool IsParameterPack,
unsigned Depth,
unsigned Position,
SourceLocation EqualLoc,
Expr *Default) {
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
// Check that we have valid decl-specifiers specified.
- auto CheckValidDeclSpecifiers = [this, &D] {
+ auto CheckValidDeclSpecifiers = [this, &DS] {
// C++ [temp.param]
// p1
// template-parameter:
@@ -924,7 +929,6 @@
// [dcl.typedef]p1:
// The typedef specifier [...] shall not be used in the decl-specifier-seq
// of a parameter-declaration
- const DeclSpec &DS = D.getDeclSpec();
auto EmitDiag = [this](SourceLocation Loc) {
Diag(Loc, diag::err_invalid_decl_specifier_in_nontype_parm)
<< FixItHint::CreateRemoval(Loc);
@@ -966,37 +970,34 @@
CheckValidDeclSpecifiers();
if (TInfo->getType()->isUndeducedType()) {
- Diag(D.getIdentifierLoc(),
+ Diag(ParamNameLoc,
diag::warn_cxx14_compat_template_nontype_parm_auto_type)
<< QualType(TInfo->getType()->getContainedAutoType(), 0);
}
assert(S->isTemplateParamScope() &&
"Non-type template parameter not in template parameter scope!");
bool Invalid = false;
- QualType T = CheckNonTypeTemplateParameterType(TInfo, D.getIdentifierLoc());
+ QualType T = CheckNonTypeTemplateParameterType(TInfo, ParamNameLoc);
if (T.isNull()) {
T = Context.IntTy; // Recover with an 'int' type.
Invalid = true;
}
- IdentifierInfo *ParamName = D.getIdentifier();
- bool IsParameterPack = D.hasEllipsis();
NonTypeTemplateParmDecl *Param
= NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
- D.getLocStart(),
- D.getIdentifierLoc(),
+ StartLoc,
+ ParamNameLoc,
Depth, Position, ParamName, T,
IsParameterPack, TInfo);
Param->setAccess(AS_public);
if (Invalid)
Param->setInvalidDecl();
if (ParamName) {
- maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
- ParamName);
+ maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
// Add the template parameter into the current scope.
S->AddDecl(Param);
@@ -2004,12 +2005,11 @@
if (OldParams)
OldParam = OldParams->begin();
- // TODO: Concepts: Replace getRequiresClause with getAssociatedConstraints
- // when we have it.
if (OldParams &&
- !CheckRedeclarationConstraintMatch(OldParams->getRequiresClause(),
- NewParams->getRequiresClause())) {
- DiagnoseRedeclarationConstraintMismatch(OldParams, NewParams);
+ !CheckRedeclarationConstraintMatch(OldParams->getAssociatedConstraints(),
+ NewParams->getAssociatedConstraints())){
+ DiagnoseRedeclarationConstraintMismatch(OldParams->getTemplateLoc(),
+ NewParams->getTemplateLoc());
Invalid = true;
}
@@ -3595,9 +3595,7 @@
if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
Converted)
&& (!Context.getLangOpts().ConceptsTS
- // TODO: Concepts: change this to getAssociatedConstraints when we
- // have them.
- || TemplateParams->getRequiresClause() == nullptr)) {
+ || TemplateParams->getAssociatedConstraints() == nullptr)) {
// C++ [temp.class.spec]p9b3:
//
// -- The argument list of the specialization shall not be identical
@@ -3618,10 +3616,7 @@
if (IsPartialSpecialization)
// FIXME: Template parameter list matters too
PrevDecl = VarTemplate->findPartialSpecialization(Converted,
- // TODO: Concepts - replace with
- // AssociatedConstraints once we
- // have them.
- TemplateParams->getRequiresClause(),
+ TemplateParams->getAssociatedConstraints(),
InsertPos);
else
PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos);
@@ -3931,20 +3926,19 @@
ExprResult
Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
ConceptDecl *Template,
SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs) {
assert(Template && "A concept template id without template?");
// Check that the template argument list is well-formed for this template.
SmallVector<TemplateArgument, 4> Converted;
- if (CheckTemplateArgumentList(Template, NameInfo.getLoc(),
+ if (CheckTemplateArgumentList(Template, TemplateLoc,
const_cast<TemplateArgumentListInfo &>(*TemplateArgs), false,
Converted, /*UpdateArgsWithConversions=*/false))
return ExprError();
- return CreateConceptSpecializationExpr(NameInfo.getLoc(), Template,
+ return CreateConceptSpecializationExpr(TemplateLoc, Template,
TemplateArgs);
}
@@ -3979,9 +3973,8 @@
}
if (R.getAsSingle<ConceptDecl>()) {
- return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
- R.getAsSingle<ConceptDecl>(),
- TemplateKWLoc, TemplateArgs);
+ return CheckConceptTemplateId(SS, R.getAsSingle<ConceptDecl>(),
+ R.getNameLoc(), TemplateArgs);
}
// We don't want lookup warnings at this point.
@@ -6768,7 +6761,6 @@
bool Complain,
Sema::TemplateParameterListEqualKind Kind,
SourceLocation TemplateArgLoc) {
- // TODO: Concepts: Check constrained-parameter constraints here.
// Check the actual kind (type, non-type, template).
if (Old->getKind() != New->getKind()) {
if (Complain) {
@@ -6813,55 +6805,67 @@
return false;
}
+ Expr *OldCE, *NewCE;
+
// For non-type template parameters, check the type of the parameter.
if (NonTypeTemplateParmDecl *OldNTTP
= dyn_cast<NonTypeTemplateParmDecl>(Old)) {
NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New);
+ OldCE = OldNTTP->getConstraintExpression();
+ NewCE = NewNTTP->getConstraintExpression();
// If we are matching a template template argument to a template
// template parameter and one of the non-type template parameter types
// is dependent, then we must wait until template instantiation time
// to actually compare the arguments.
- if (Kind == Sema::TPL_TemplateTemplateArgumentMatch &&
- (OldNTTP->getType()->isDependentType() ||
- NewNTTP->getType()->isDependentType()))
- return true;
-
- if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
- if (Complain) {
- unsigned NextDiag = diag::err_template_nontype_parm_different_type;
- if (TemplateArgLoc.isValid()) {
- S.Diag(TemplateArgLoc,
- diag::err_template_arg_template_params_mismatch);
- NextDiag = diag::note_template_nontype_parm_different_type;
+ if (Kind != Sema::TPL_TemplateTemplateArgumentMatch ||
+ (!OldNTTP->getType()->isDependentType() &&
+ !NewNTTP->getType()->isDependentType()))
+ if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) {
+ if (Complain) {
+ unsigned NextDiag = diag::err_template_nontype_parm_different_type;
+ if (TemplateArgLoc.isValid()) {
+ S.Diag(TemplateArgLoc,
+ diag::err_template_arg_template_params_mismatch);
+ NextDiag = diag::note_template_nontype_parm_different_type;
+ }
+ S.Diag(NewNTTP->getLocation(), NextDiag)
+ << NewNTTP->getType()
+ << (Kind != Sema::TPL_TemplateMatch);
+ S.Diag(OldNTTP->getLocation(),
+ diag::note_template_nontype_parm_prev_declaration)
+ << OldNTTP->getType();
}
- S.Diag(NewNTTP->getLocation(), NextDiag)
- << NewNTTP->getType()
- << (Kind != Sema::TPL_TemplateMatch);
- S.Diag(OldNTTP->getLocation(),
- diag::note_template_nontype_parm_prev_declaration)
- << OldNTTP->getType();
- }
-
- return false;
- }
- return true;
+ return false;
+ }
}
-
// For template template parameters, check the template parameter types.
// The template parameter lists of template template
// parameters must agree.
- if (TemplateTemplateParmDecl *OldTTP
+ else if (TemplateTemplateParmDecl *OldTTP
= dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
- return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
- OldTTP->getTemplateParameters(),
- Complain,
+ OldCE = OldTTP->getConstraintExpression();
+ NewCE = NewTTP->getConstraintExpression();
+ if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(),
+ OldTTP->getTemplateParameters(),
+ Complain,
(Kind == Sema::TPL_TemplateMatch
? Sema::TPL_TemplateTemplateParmMatch
: Kind),
- TemplateArgLoc);
+ TemplateArgLoc))
+ return false;
+ } else {
+ OldCE = cast<TemplateTypeParmDecl>(Old)->getConstraintExpression();
+ NewCE = cast<TemplateTypeParmDecl>(New)->getConstraintExpression();
+ }
+
+ if (!S.CheckRedeclarationConstraintMatch(OldCE, NewCE)) {
+ if (Complain)
+ S.DiagnoseRedeclarationConstraintMismatch(Old->getLocStart(),
+ New->getLocStart());
+ return false;
}
return true;
@@ -6978,10 +6982,14 @@
return false;
}
- if (!CheckRedeclarationConstraintMatch(Old->getRequiresClause(),
- New->getRequiresClause())) {
+ Expr *OldRC = Old->getRequiresClause(),
+ *NewRC = New->getRequiresClause();
+ if (!CheckRedeclarationConstraintMatch(OldRC, NewRC)) {
if (Complain)
- DiagnoseRedeclarationConstraintMismatch(Old, New);
+ DiagnoseRedeclarationConstraintMismatch(OldRC ? OldRC->getLocStart()
+ : Old->getTemplateLoc(),
+ NewRC ? NewRC->getLocStart()
+ : New->getTemplateLoc());
return false;
}
@@ -7535,10 +7543,7 @@
if (isPartialSpecialization)
// FIXME: Template parameter list matters, too
PrevDecl = ClassTemplate->findPartialSpecialization(Converted,
- // TODO: Concepts: Replace with
- // AssociatedConstraints once we
- // have them.
- TemplateParams->getRequiresClause(),
+ TemplateParams->getAssociatedConstraints(),
InsertPos);
else
PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos);
@@ -7565,9 +7570,7 @@
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization())
&& (!Context.getLangOpts().ConceptsTS
- // TODO: Concepts: change this to getAssociatedConstraints when we
- // have them.
- || TemplateParams->getRequiresClause() == nullptr)) {
+ || TemplateParams->getAssociatedConstraints() == nullptr)) {
// C++ [temp.class.spec]p9b3:
//
// -- The argument list of the specialization shall not be identical
Index: lib/Sema/SemaConcept.cpp
===================================================================
--- lib/Sema/SemaConcept.cpp
+++ lib/Sema/SemaConcept.cpp
@@ -63,13 +63,11 @@
}
void
-Sema::DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old,
- const TemplateParameterList *New){
- Diag(New->getTemplateLoc(),
- diag::err_template_different_associated_constraints);
+Sema::DiagnoseRedeclarationConstraintMismatch(SourceLocation Old,
+ SourceLocation New){
+ Diag(New, diag::err_template_different_associated_constraints);
- Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration)
- << /*declaration*/0;
+ Diag(Old, diag::note_template_prev_declaration) << /*declaration*/0;
}
template <typename AtomicEvaluator>
Index: lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- lib/Sema/SemaCXXScopeSpec.cpp
+++ lib/Sema/SemaCXXScopeSpec.cpp
@@ -462,6 +462,7 @@
/// 'true' if the identifier is treated as if it was followed by ':',
/// not '::'.
/// \param OnlyNamespace If true, only considers namespaces in lookup.
+/// \param SuppressDiagnostics If true, will not emit diagnostics on an error.
///
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
/// that it contains an extra parameter \p ScopeLookupResult, which provides
@@ -479,7 +480,8 @@
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
bool *IsCorrectedToColon,
- bool OnlyNamespace) {
+ bool OnlyNamespace,
+ bool SuppressDiagnostics) {
if (IdInfo.Identifier->isEditorPlaceholder())
return true;
LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc,
@@ -574,7 +576,7 @@
return false;
}
- if (Found.empty() && !ErrorRecoveryLookup) {
+ if (Found.empty() && !ErrorRecoveryLookup && !SuppressDiagnostics) {
// If identifier is not found as class-name-or-namespace-name, but is found
// as other entity, don't look for typos.
LookupResult R(*this, Found.getLookupNameInfo(), LookupOrdinaryName);
@@ -608,7 +610,8 @@
}
}
- if (Found.empty() && !ErrorRecoveryLookup && !getLangOpts().MSVCCompat) {
+ if (Found.empty() && !ErrorRecoveryLookup && !SuppressDiagnostics
+ && !getLangOpts().MSVCCompat) {
// We haven't found anything, and we're not recovering from a
// different kind of error, so look for typos.
DeclarationName Name = Found.getLookupName();
@@ -678,7 +681,7 @@
!Context.hasSameType(
Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)),
Context.getTypeDeclType(cast<TypeDecl>(SD))))) {
- if (ErrorRecoveryLookup)
+ if (ErrorRecoveryLookup || SuppressDiagnostics)
return true;
Diag(IdInfo.IdentifierLoc,
@@ -760,7 +763,7 @@
// Otherwise, we have an error case. If we don't want diagnostics, just
// return an error now.
- if (ErrorRecoveryLookup)
+ if (ErrorRecoveryLookup || SuppressDiagnostics)
return true;
// If we didn't find anything during our lookup, try again with
@@ -828,13 +831,15 @@
bool EnteringContext, CXXScopeSpec &SS,
bool ErrorRecoveryLookup,
bool *IsCorrectedToColon,
- bool OnlyNamespace) {
+ bool OnlyNamespace,
+ bool SuppressDiagnostic) {
if (SS.isInvalid())
return true;
return BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS,
/*ScopeLookupResult=*/nullptr, false,
- IsCorrectedToColon, OnlyNamespace);
+ IsCorrectedToColon, OnlyNamespace,
+ SuppressDiagnostic);
}
bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/RAIIObjectsForParser.h"
@@ -532,29 +533,152 @@
/// template-parameter: [C++ temp.param]
/// type-parameter
/// parameter-declaration
+/// constrained-parameter
+///
+/// type-parameter: (See below)
+/// type-parameter-key ...[opt] identifier[opt]
+/// type-parameter-key identifier[opt] = type-id
+/// 'template' '<' template-parameter-list '>' type-parameter-key
+/// ...[opt] identifier[opt]
+/// 'template' '<' template-parameter-list '>' type-parameter-key
+/// identifier[opt] '=' id-expression
+///
+/// type-parameter-key:
+/// class
+/// typename
+///
+/// constrained-parameter:
+/// qualified-concept-name ... identifier[opt]
+/// qualified-concept-name identifier[opt]
+/// default-template-argument[opt]
+///
+/// qualified-concept-name:
+/// nested-name-specifier[opt] concept-name
+/// nested-name-specifier[opt] partial-concept-id
+///
+/// partial-concept-id:
+/// concept-name '<' template-argument-list[opt] '>'
+///
+/// default-template-argument:
+/// = type-id
+/// = id-expression
+/// = initializer-clause
///
-/// type-parameter: (see below)
-/// 'class' ...[opt] identifier[opt]
-/// 'class' identifier[opt] '=' type-id
-/// 'typename' ...[opt] identifier[opt]
-/// 'typename' identifier[opt] '=' type-id
-/// 'template' '<' template-parameter-list '>'
-/// 'class' ...[opt] identifier[opt]
-/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
-/// = id-expression
Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
if (isStartOfTemplateTypeParameter())
return ParseTypeParameter(Depth, Position);
if (Tok.is(tok::kw_template))
return ParseTemplateTemplateParameter(Depth, Position);
+ // At this point we're either facing a constrained-parameter or a typename for
+ // a non type template parameter.
+ SourceLocation ParamStartLoc = Tok.getLocation();
+ ConceptDecl *CD;
+ SourceLocation ConceptNameLoc;
+ TemplateArgumentListInfo TALI;
+ if (TryParseConstrainedParameter(CD, ConceptNameLoc, TALI)) {
+ if (!CD)
+ // This is definitely a constrained parameter but there's been an error
+ // parsing it.
+ return nullptr;
+ return ParseConstrainedTemplateParameter(Depth, Position, ParamStartLoc,
+ CD, std::move(TALI));
+ }
+
// If it's none of the above, then it must be a parameter declaration.
// NOTE: This will pick up errors in the closure of the template parameter
// list (e.g., template < ; Check here to implement >> style closures.
return ParseNonTypeTemplateParameter(Depth, Position);
}
+
+/// Try parsing a constrained-parameter construct at the current location. A
+/// constrained-parameter names a concept along with an optional set of template
+/// arguments, and denotes a placeholder that accepts entities that (along with
+/// the set of arguments, if any) satisfy the concept.
+/// \returns true if there is a constrained-parameter at the current location,
+/// false otherwise. If an error occured while parsing the
+/// constrained-parameter, the returned CD will be nullptr.
+bool Parser::TryParseConstrainedParameter(ConceptDecl *&CD,
+ SourceLocation &ConceptNameLoc,
+ TemplateArgumentListInfo &TALI) {
+ TentativeParsingAction TPA(*this);
+ CXXScopeSpec SS;
+
+ if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+ /*EnteringContext=*/false,
+ /*MayBePseudoDestructor=*/nullptr,
+ /*IsTypename=*/false,
+ /*LastII=*/nullptr,
+ /*OnlyNamespace=*/true,
+ /*SuppressDiagnostics=*/true)) {
+ TPA.Revert();
+ return false;
+ }
+
+ if (!Tok.is(tok::identifier)) {
+ TPA.Revert();
+ return false;
+ }
+
+ UnqualifiedId PossibleConceptName;
+ PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(),
+ Tok.getLocation());
+ ConceptNameLoc = ConsumeToken();
+
+ TemplateTy PossibleConcept;
+ bool MemberOfUnknownSpecialization = false;
+ auto TNK = Actions.isTemplateName(getCurScope(), SS,
+ /*hasTemplateKeyword=*/false,
+ PossibleConceptName,
+ /*ObjectType=*/ParsedType(),
+ /*EnteringContext=*/false,
+ PossibleConcept,
+ MemberOfUnknownSpecialization);
+ assert(!MemberOfUnknownSpecialization
+ && "Member when we only allowed namespace scope qualifiers??");
+ if (!PossibleConcept || TNK != TNK_Concept_template) {
+ TPA.Revert();
+ return false;
+ }
+
+ TPA.Commit();
+
+ // At this point we're sure we're dealing with a constrained parameter. It
+ // may or may not have a template parameter list following the concept name.
+ if (Tok.is(tok::less)) {
+ if (AnnotateTemplateIdToken(PossibleConcept, TNK, SS,
+ /*TemplateKWLoc=*/SourceLocation(),
+ PossibleConceptName,
+ /*AllowTypeAnnotation=*/false)) {
+ CD = nullptr;
+ return true;
+ }
+ auto *TemplateId = (TemplateIdAnnotation*)Tok.getAnnotationValue();
+ TALI.setLAngleLoc(TemplateId->LAngleLoc);
+ TALI.setRAngleLoc(TemplateId->RAngleLoc);
+ // Translate the parser's template argument list into our AST format.
+ Actions.translateTemplateArguments(
+ MutableArrayRef<ParsedTemplateArgument>(
+ TemplateId->getTemplateArgs(),
+ TemplateId->NumArgs), TALI);
+ ConsumeAnnotationToken();
+ }
+
+ CD = cast<ConceptDecl>(PossibleConcept.get().getAsTemplateDecl());
+
+ // If the user did not use a partial concept id and the concept does not
+ // accept a single argument or parameter pack, fail now with a nicer error
+ // message
+ if (TALI.size() == 0
+ && CD->getTemplateParameters()->getMinRequiredArguments() > 1) {
+ Diag(diag::err_constrained_parameter_missing_arguments) << CD;
+ CD = nullptr;
+ }
+ return true;
+}
+
/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
/// Other kinds of template parameters are parsed in
/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
@@ -774,11 +898,215 @@
}
// Create the parameter.
- return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl,
+ return Actions.ActOnNonTypeTemplateParameter(getCurScope(),
+ ParamDecl.getDeclSpec(),
+ ParamDecl.getLocStart(),
+ Actions.GetTypeForDeclarator(
+ ParamDecl, getCurScope()),
+ ParamDecl.getIdentifier(),
+ ParamDecl.getIdentifierLoc(),
+ ParamDecl.hasEllipsis(),
Depth, Position, EqualLoc,
DefaultArg.get());
}
+Decl *
+Parser::ParseConstrainedTemplateParameter(unsigned Depth, unsigned Position,
+ SourceLocation ParamStartLoc,
+ ConceptDecl *CD,
+ TemplateArgumentListInfo TALI) {
+ // Grab the ellipsis (if given).
+ SourceLocation EllipsisLoc;
+ TryConsumeToken(tok::ellipsis, EllipsisLoc);
+
+ // Grab the template parameter name (if given)
+ SourceLocation NameLoc;
+ IdentifierInfo *ParamName = nullptr;
+ if (Tok.is(tok::identifier)) {
+ ParamName = Tok.getIdentifierInfo();
+ NameLoc = ConsumeToken();
+ } else if (Tok.isOneOf(tok::equal, tok::comma, tok::greater,
+ tok::greatergreater)) {
+ // Unnamed template parameter. Don't have to do anything here, just
+ // don't consume this token.
+ } else {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ return nullptr;
+ }
+
+ // Recover from misplaced ellipsis.
+ bool AlreadyHasEllipsis = EllipsisLoc.isValid();
+ if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
+ DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis,
+ true);
+
+ // Grab a default argument (if available).
+ // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before
+ // we introduce the type parameter into the local scope.
+ SourceLocation EqualLoc;
+
+ NamedDecl *DeclaredParm = nullptr;
+ NamedDecl *ConceptPrototypeParameter = *CD->getTemplateParameters()->begin();
+ if (TemplateTypeParmDecl *TypeP = dyn_cast<TemplateTypeParmDecl>(
+ ConceptPrototypeParameter)) {
+ ParsedType DefaultArg;
+ if (TryConsumeToken(tok::equal, EqualLoc))
+ DefaultArg = ParseTypeName(/*SourceRange=*/nullptr,
+ Declarator::TemplateTypeArgContext)
+ .get();
+ DeclaredParm = cast_or_null<NamedDecl>(
+ Actions.ActOnTypeParameter(getCurScope(),
+ TypeP->wasDeclaredWithTypename(),
+ EllipsisLoc, ParamStartLoc, ParamName,
+ NameLoc, Depth, Position, EqualLoc,
+ DefaultArg));
+ if (!DeclaredParm)
+ return nullptr;
+
+ QualType Q(cast<TemplateTypeParmDecl>(DeclaredParm)->getTypeForDecl(),
+ 0);
+ if (!EllipsisLoc.isInvalid()
+ && CD->getTemplateParameters()->hasParameterPack())
+ // C++ [temp.param]p11.1
+ // If P declares a template parameter pack and C is a variadic concept,
+ // then A is the pack expansion P... . Otherwise, A is the
+ // id-expression P.
+ Q = Actions.Context.getPackExpansionType(Q, /*NumExpansions=*/None);
+ TALI.prependArgument(
+ TemplateArgumentLoc(TemplateArgument(Q),
+ TemplateArgumentLocInfo(
+ Actions.Context.getTrivialTypeSourceInfo(Q))));
+ } else if (TemplateTemplateParmDecl *TemplateP =
+ dyn_cast<TemplateTemplateParmDecl>(ConceptPrototypeParameter)) {
+ ParsedTemplateArgument DefaultArg;
+ if (TryConsumeToken(tok::equal, EqualLoc)) {
+ DefaultArg = ParseTemplateTemplateArgument();
+ if (DefaultArg.isInvalid()) {
+ Diag(Tok.getLocation(),
+ diag::err_default_template_template_parameter_not_template);
+ SkipUntil(tok::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
+ }
+ }
+
+
+ DeclaredParm = cast_or_null<NamedDecl>(
+ Actions.ActOnTemplateTemplateParameter(getCurScope(),
+ ParamStartLoc,
+ TemplateP->getTemplateParameters(),
+ EllipsisLoc, ParamName,
+ NameLoc, Depth, Position,
+ EqualLoc, DefaultArg));
+ if (!DeclaredParm)
+ return nullptr;
+ TemplateName TemplName(cast_or_null<TemplateDecl>(DeclaredParm));
+
+ // C++ [temp.param]p11.1
+ // If P declares a template parameter pack and C is a variadic concept,
+ // then A is the pack expansion P... . Otherwise, A is the
+ // id-expression P.
+ bool ShouldExpand = !EllipsisLoc.isInvalid()
+ && CD->getTemplateParameters()->hasParameterPack();
+
+ NestedNameSpecifierLocBuilder Builder;
+ TemplateArgumentLocInfo LocInf(Builder.getWithLocInContext(Actions.Context),
+ NameLoc, EllipsisLoc);
+ TemplateArgumentLoc TAL(ShouldExpand
+ ? TemplateArgument(TemplName, Optional<unsigned>())
+ : TemplateArgument(TemplName), LocInf);
+ TALI.prependArgument(TAL);
+ } else if (NonTypeTemplateParmDecl *NonTypeP =
+ dyn_cast<NonTypeTemplateParmDecl>(ConceptPrototypeParameter)) {
+ ExprResult DefaultArg;
+ if (TryConsumeToken(tok::equal, EqualLoc)) {
+ // C++ [temp.param]p15:
+ // When parsing a default template-argument for a non-type
+ // template-parameter, the first non-nested > is taken as the
+ // end of the template-parameter-list rather than a greater-than
+ // operator.
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ DefaultArg = Actions.CorrectDelayedTyposInExpr(
+ ParseAssignmentExpression());
+ if (DefaultArg.isInvalid())
+ SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
+ }
+
+ DeclaredParm = cast_or_null<NamedDecl>(
+ Actions.ActOnNonTypeTemplateParameter(getCurScope(),
+ DeclSpec(getAttrFactory()),
+ ParamStartLoc,
+ NonTypeP->getTypeSourceInfo(),
+ ParamName, NameLoc,
+ EllipsisLoc.isValid(),
+ Depth, Position, EqualLoc,
+ DefaultArg.isInvalid() ? nullptr :
+ DefaultArg.get()));
+ if (!DeclaredParm)
+ return nullptr;
+
+ ValueDecl *VD = cast<ValueDecl>(DeclaredParm);
+ Expr *DerivedArgument =
+ new (Actions.Context) DeclRefExpr(VD,
+ /*RefersToEnclosingVariableOrCapture=*/false,
+ VD->getType(), VK_LValue, NameLoc,
+ DeclarationNameLoc(VD->getDeclName()));
+ // C++ [temp.param]p11.1
+ // If P declares a template parameter pack and C is a variadic concept,
+ // then A is the pack expansion P... . Otherwise, A is the
+ // id-expression P.
+ if (EllipsisLoc.isValid()
+ && CD->getTemplateParameters()->hasParameterPack())
+ DerivedArgument =
+ new (Actions.Context) PackExpansionExpr(Actions.Context.DependentTy,
+ DerivedArgument, EllipsisLoc,
+ /*NumExpansions=*/None);
+ TemplateArgument DeclaredParmA(DerivedArgument);
+ TALI.prependArgument(
+ TemplateArgumentLoc(DeclaredParmA,
+ TemplateArgumentLocInfo(DerivedArgument)));
+ } else
+ llvm_unreachable("Unrecognized concept prototype parameter type.");
+
+ // We now have an actual template parameter declared - form the constraint
+ // expression and attach it to the declared parameter.
+
+ CXXScopeSpec SS;
+ ExprResult Result = Actions.CheckConceptTemplateId(SS, CD, ParamStartLoc,
+ &TALI);
+ if (Result.isInvalid() || !Result.isUsable())
+ // Just ignore the constraint and attempt to continue.
+ return DeclaredParm;
+
+ Expr *IntroducedConstraint = Result.get();
+ if (EllipsisLoc.isValid() && !CD->getTemplateParameters()->hasParameterPack())
+ // We have the following case:
+ //
+ // template<typename T> concept C1 = true;
+ // template<C1... T> struct s1;
+ //
+ // The constraint: (C1<T> && ...)
+ IntroducedConstraint =
+ Actions.ActOnCXXFoldExpr(/*LParenLoc=*/SourceLocation(),
+ IntroducedConstraint, tok::ampamp,
+ EllipsisLoc, /*RHS=*/nullptr,
+ /*RParenLoc=*/SourceLocation()).get();
+
+ if (TemplateTypeParmDecl *TypeP =
+ dyn_cast<TemplateTypeParmDecl>(DeclaredParm))
+ TypeP->setConstraintExpression(IntroducedConstraint);
+ else if (TemplateTemplateParmDecl *TemplateP =
+ dyn_cast<TemplateTemplateParmDecl>(DeclaredParm))
+ TemplateP->setConstraintExpression(IntroducedConstraint);
+ else
+ cast<NonTypeTemplateParmDecl>(DeclaredParm)
+ ->setConstraintExpression(IntroducedConstraint);
+
+ return DeclaredParm;
+}
+
void Parser::DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
SourceLocation CorrectLoc,
bool AlreadyHasEllipsis,
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -143,14 +143,18 @@
///
/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
+/// \param SuppressDiagnostic If true, suppress diagnostic on incorrect scope
+/// specifier.
+///
/// \returns true if there was an error parsing a scope specifier
bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
ParsedType ObjectType,
bool EnteringContext,
bool *MayBePseudoDestructor,
bool IsTypename,
IdentifierInfo **LastII,
- bool OnlyNamespace) {
+ bool OnlyNamespace,
+ bool SuppressDiagnostic) {
assert(getLangOpts().CPlusPlus &&
"Call sites of this function should be guarded by checking for C++");
@@ -455,7 +459,7 @@
bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
if (Actions.ActOnCXXNestedNameSpecifier(
getCurScope(), IdInfo, EnteringContext, SS, false,
- CorrectionFlagPtr, OnlyNamespace)) {
+ CorrectionFlagPtr, OnlyNamespace, SuppressDiagnostic)) {
// Identifier is not recognized as a nested name, but we can have
// mistyped '::' instead of ':'.
if (CorrectionFlagPtr && IsCorrectedToColon) {
@@ -476,6 +480,11 @@
// nested-name-specifier:
// type-name '<'
if (Next.is(tok::less)) {
+ if (OnlyNamespace)
+ // We can't have template-ids as part of a namespace scope specifier,
+ // the scope specifier must end here.
+ break;
+
TemplateTy Template;
UnqualifiedId TemplateName;
TemplateName.setIdentifier(&II, Tok.getLocation());
@@ -2440,14 +2449,17 @@
///
/// \param Result on a successful parse, contains the parsed unqualified-id.
///
+/// \param SuppressDiag whether to suppress the diagnostic when an unqualified
+/// id was not found at the current location.
+///
/// \returns true if parsing fails, false otherwise.
bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,
bool AllowConstructorName,
bool AllowDeductionGuide,
ParsedType ObjectType,
SourceLocation& TemplateKWLoc,
- UnqualifiedId &Result) {
+ UnqualifiedId &Result, bool SuppressDiag) {
// Handle 'A::template B'. This is for template-ids which have not
// already been annotated by ParseOptionalCXXScopeSpecifier().
@@ -2649,9 +2661,10 @@
Result.setDestructorName(TildeLoc, Ty, ClassNameLoc);
return false;
}
-
- Diag(Tok, diag::err_expected_unqualified_id)
- << getLangOpts().CPlusPlus;
+
+ if (!SuppressDiag)
+ Diag(Tok, diag::err_expected_unqualified_id)
+ << getLangOpts().CPlusPlus;
return true;
}
Index: lib/AST/ODRHash.cpp
===================================================================
--- lib/AST/ODRHash.cpp
+++ lib/AST/ODRHash.cpp
@@ -365,6 +365,11 @@
AddTemplateArgument(D->getDefaultArgument());
}
+ Expr *CE = D->getConstraintExpression();
+ Hash.AddBoolean(CE != nullptr);
+ if (CE)
+ AddStmt(CE);
+
Inherited::VisitTemplateTypeParmDecl(D);
}
@@ -377,6 +382,11 @@
AddStmt(D->getDefaultArgument());
}
+ Expr *CE = D->getConstraintExpression();
+ Hash.AddBoolean(CE != nullptr);
+ if (CE)
+ AddStmt(CE);
+
Inherited::VisitNonTypeTemplateParmDecl(D);
}
@@ -389,6 +399,11 @@
AddTemplateArgument(D->getDefaultArgument().getArgument());
}
+ Expr *CE = D->getConstraintExpression();
+ Hash.AddBoolean(CE != nullptr);
+ if (CE)
+ AddStmt(CE);
+
Inherited::VisitTemplateTemplateParmDecl(D);
}
};
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -43,14 +43,30 @@
// TemplateParameterList Implementation
//===----------------------------------------------------------------------===//
-TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
+// Create a constraint expression as the conjunction (the "and") of two other
+// constraint expressions.
+static Expr *CreateConstraintConjunction(const ASTContext &C, Expr *A, Expr *B){
+ if (!A) {
+ return B;
+ }
+ if (B) {
+ return new (C) BinaryOperator(A, B, BO_LAnd, C.BoolTy, VK_RValue,
+ OK_Ordinary, /*opLoc=*/SourceLocation(),
+ FPOptions());
+ }
+ return A;
+}
+
+TemplateParameterList::TemplateParameterList(const ASTContext& C,
+ SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc,
- Expr *RequiresClause)
+ Expr *RequiresClause,
+ Expr *ConstrainedParamsConstraints)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumParams(Params.size()), ContainsUnexpandedParameterPack(false),
- HasRequiresClause(static_cast<bool>(RequiresClause)) {
+ HasAssociatedConstraints(ConstrainedParamsConstraints || RequiresClause) {
for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
NamedDecl *P = Params[Idx];
begin()[Idx] = P;
@@ -68,23 +84,41 @@
// template parameter list does too.
}
}
- if (RequiresClause) {
- *getTrailingObjects<Expr *>() = RequiresClause;
- if (RequiresClause->containsUnexpandedParameterPack())
+ if (HasAssociatedConstraints) {
+ if ((RequiresClause && RequiresClause->containsUnexpandedParameterPack()) ||
+ (ConstrainedParamsConstraints &&
+ ConstrainedParamsConstraints->containsUnexpandedParameterPack()))
ContainsUnexpandedParameterPack = true;
+ Expr **ACStorage = getTrailingObjects<Expr *>();
+ ACStorage[0] = RequiresClause;
+ ACStorage[1] = CreateConstraintConjunction(C, RequiresClause,
+ ConstrainedParamsConstraints);
}
}
TemplateParameterList *
TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc, Expr *RequiresClause) {
+ Expr *AC = nullptr;
+ for (NamedDecl *P : Params)
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
+ if (Expr *CE = NTTP->getConstraintExpression())
+ AC = CreateConstraintConjunction(C, AC, CE);
+ } else if (TemplateTemplateParmDecl *TTP =
+ dyn_cast<TemplateTemplateParmDecl>(P)) {
+ if (Expr *CE = TTP->getConstraintExpression())
+ AC = CreateConstraintConjunction(C, AC, CE);
+ } else
+ if (Expr *CE = cast<TemplateTypeParmDecl>(P)->getConstraintExpression())
+ AC = CreateConstraintConjunction(C, AC, CE);
+
void *Mem = C.Allocate(totalSizeToAlloc<NamedDecl *, Expr *>(
- Params.size(), RequiresClause ? 1u : 0u),
+ Params.size(), RequiresClause || AC ? 2u : 0u),
alignof(TemplateParameterList));
- return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
- RAngleLoc, RequiresClause);
+ return new (Mem) TemplateParameterList(C, TemplateLoc, LAngleLoc, Params,
+ RAngleLoc, RequiresClause, AC);
}
unsigned TemplateParameterList::getMinRequiredArguments() const {
@@ -148,27 +182,11 @@
} // namespace clang
-// Create a constraint expression as the conjunction (the "and") of two other
-// constraint expressions.
-static Expr *CreateConstraintConjunction(ASTContext &C, Expr *A, Expr *B) {
- if (!A) {
- return B;
- }
- if (B) {
- return new (C) BinaryOperator(A, B, BO_LAnd, C.BoolTy, VK_RValue,
- OK_Ordinary, /*opLoc=*/SourceLocation(),
- FPOptions());
- }
- return A;
-}
-
static ConstrainedTemplateDeclInfo *
collectAssociatedConstraints(ASTContext &C, TemplateParameterList *Params,
Expr *TrailingRequiresClause = nullptr) {
- // TODO: Instead of calling getRequiresClause - write and call a
- // TemplateParameterList member function calculateAssociatedConstraints, which
- // will also fetch constraint-expressions from constrained-parameters.
- Expr *TotalAC = CreateConstraintConjunction(C, Params->getRequiresClause(),
+ Expr *TotalAC = CreateConstraintConjunction(C,
+ Params->getAssociatedConstraints(),
TrailingRequiresClause);
if (TotalAC) {
ConstrainedTemplateDeclInfo *CTDI = new (C) ConstrainedTemplateDeclInfo;
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ lib/AST/ASTImporter.cpp
@@ -3696,15 +3696,17 @@
// is created.
// FIXME: Import default argument.
- return TemplateTypeParmDecl::Create(Importer.getToContext(),
- Importer.getToContext().getTranslationUnitDecl(),
- Importer.Import(D->getLocStart()),
- Importer.Import(D->getLocation()),
- D->getDepth(),
- D->getIndex(),
- Importer.Import(D->getIdentifier()),
- D->wasDeclaredWithTypename(),
- D->isParameterPack());
+ auto *R = TemplateTypeParmDecl::Create(Importer.getToContext(),
+ Importer.getToContext().getTranslationUnitDecl(),
+ Importer.Import(D->getLocStart()),
+ Importer.Import(D->getLocation()),
+ D->getDepth(), D->getIndex(),
+ Importer.Import(D->getIdentifier()),
+ D->wasDeclaredWithTypename(),
+ D->isParameterPack());
+ if (Expr *CE = D->getConstraintExpression())
+ R->setConstraintExpression(VisitExpr(CE));
+ return R;
}
Decl *
@@ -3729,12 +3731,15 @@
// FIXME: Import default argument.
- return NonTypeTemplateParmDecl::Create(Importer.getToContext(),
+ auto *R = NonTypeTemplateParmDecl::Create(Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
- Importer.Import(D->getInnerLocStart()),
- Loc, D->getDepth(), D->getPosition(),
- Name.getAsIdentifierInfo(),
- T, D->isParameterPack(), TInfo);
+ Importer.Import(D->getInnerLocStart()),
+ Loc, D->getDepth(), D->getPosition(),
+ Name.getAsIdentifierInfo(), T,
+ D->isParameterPack(), TInfo);
+ if (Expr *CE = D->getConstraintExpression())
+ R->setConstraintExpression(VisitExpr(CE));
+ return R;
}
Decl *
@@ -3754,13 +3759,14 @@
return nullptr;
// FIXME: Import default argument.
-
- return TemplateTemplateParmDecl::Create(Importer.getToContext(),
- Importer.getToContext().getTranslationUnitDecl(),
- Loc, D->getDepth(), D->getPosition(),
- D->isParameterPack(),
- Name.getAsIdentifierInfo(),
- TemplateParams);
+ auto *R = TemplateTemplateParmDecl::Create(Importer.getToContext(),
+ Importer.getToContext().getTranslationUnitDecl(),
+ Loc, D->getDepth(), D->getPosition(),
+ D->isParameterPack(), Name.getAsIdentifierInfo(),
+ TemplateParams);
+ if (Expr *CE = D->getConstraintExpression())
+ R->setConstraintExpression(VisitExpr(CE));
+ return R;
}
Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -1649,6 +1649,10 @@
if (D->isParameterPack())
OS << " ...";
dumpName(D);
+ if (Expr *CE = D->getConstraintExpression()) {
+ OS << " requires ";
+ dumpStmt(CE);
+ }
if (D->hasDefaultArgument())
dumpTemplateArgument(D->getDefaultArgument());
}
@@ -1659,6 +1663,10 @@
if (D->isParameterPack())
OS << " ...";
dumpName(D);
+ if (Expr *CE = D->getConstraintExpression()) {
+ OS << " requires ";
+ dumpStmt(CE);
+ }
if (D->hasDefaultArgument())
dumpTemplateArgument(D->getDefaultArgument());
}
@@ -1670,6 +1678,10 @@
OS << " ...";
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
+ if (Expr *CE = D->getConstraintExpression()) {
+ OS << " requires ";
+ dumpStmt(CE);
+ }
if (D->hasDefaultArgument())
dumpTemplateArgumentLoc(D->getDefaultArgument());
}
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -699,8 +699,8 @@
cast<TemplateTemplateParmDecl>(*P)));
}
- assert(!TTP->getTemplateParameters()->getRequiresClause() &&
- "Unexpected requires-clause on template template-parameter");
+ assert(!TTP->getAssociatedConstraints() &&
+ "Unexpected constraints on template template-parameter");
Expr *const CanonRequiresClause = nullptr;
TemplateTemplateParmDecl *CanonTTP
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5327,7 +5327,8 @@
NamedDecl *ScopeLookupResult,
bool ErrorRecoveryLookup,
bool *IsCorrectedToColon = nullptr,
- bool OnlyNamespace = false);
+ bool OnlyNamespace = false,
+ bool SuppressDiagnostics = false);
/// \brief The parser has parsed a nested-name-specifier 'identifier::'.
///
@@ -5353,14 +5354,17 @@
///
/// \param OnlyNamespace If true, only considers namespaces in lookup.
///
+ /// \param SuppressDiagnostic If true, suppress diagnostic on error.
+ ///
/// \returns true if an error occurred, false otherwise.
bool ActOnCXXNestedNameSpecifier(Scope *S,
NestedNameSpecInfo &IdInfo,
bool EnteringContext,
CXXScopeSpec &SS,
bool ErrorRecoveryLookup = false,
bool *IsCorrectedToColon = nullptr,
- bool OnlyNamespace = false);
+ bool OnlyNamespace = false,
+ bool SuppressDiagnostic = false);
ExprResult ActOnDecltypeExpression(Expr *E);
@@ -5658,8 +5662,8 @@
void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation,
StringRef Diagnostic);
- void DiagnoseRedeclarationConstraintMismatch(const TemplateParameterList *Old,
- const TemplateParameterList *New);
+ void DiagnoseRedeclarationConstraintMismatch(SourceLocation Old,
+ SourceLocation New);
// ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
@@ -6166,11 +6170,17 @@
SourceLocation Loc);
QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc);
- Decl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
+ Decl *ActOnNonTypeTemplateParameter(Scope *S,
+ const DeclSpec &DS,
+ SourceLocation StartLoc,
+ TypeSourceInfo *TInfo,
+ IdentifierInfo *ParamName,
+ SourceLocation ParamNameLoc,
+ bool IsParameterPack,
unsigned Depth,
unsigned Position,
SourceLocation EqualLoc,
- Expr *DefaultArg);
+ Expr *Default);
Decl *ActOnTemplateTemplateParameter(Scope *S,
SourceLocation TmpLoc,
TemplateParameterList *Params,
@@ -6277,9 +6287,7 @@
const TemplateArgumentListInfo *TemplateArgs);
ExprResult
- CheckConceptTemplateId(const CXXScopeSpec &SS,
- const DeclarationNameInfo &NameInfo,
- ConceptDecl *Template,
+ CheckConceptTemplateId(const CXXScopeSpec &SS, ConceptDecl *Template,
SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs);
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -1584,7 +1584,8 @@
bool *MayBePseudoDestructor = nullptr,
bool IsTypename = false,
IdentifierInfo **LastII = nullptr,
- bool OnlyNamespace = false);
+ bool OnlyNamespace = false,
+ bool SuppressDiagnostic = false);
//===--------------------------------------------------------------------===//
// C++0x 5.1.2: Lambda expressions
@@ -2719,7 +2720,7 @@
bool AllowDeductionGuide,
ParsedType ObjectType,
SourceLocation& TemplateKWLoc,
- UnqualifiedId &Result);
+ UnqualifiedId &Result, bool SuppressDiag = false);
private:
//===--------------------------------------------------------------------===//
@@ -2752,6 +2753,13 @@
Decl *ParseTypeParameter(unsigned Depth, unsigned Position);
Decl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position);
Decl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position);
+ bool TryParseConstrainedParameter(ConceptDecl *&CD,
+ SourceLocation &ConceptNameLoc,
+ TemplateArgumentListInfo &TALI);
+ Decl *ParseConstrainedTemplateParameter(unsigned Depth, unsigned Position,
+ SourceLocation ParamStartLoc,
+ ConceptDecl *CD,
+ TemplateArgumentListInfo TALI);
void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc,
SourceLocation CorrectLoc,
bool AlreadyHasEllipsis,
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -666,6 +666,9 @@
def err_explicit_instantiation_enum : Error<
"enumerations cannot be explicitly instantiated">;
def err_expected_template_parameter : Error<"expected template parameter">;
+def err_constrained_parameter_missing_arguments : Error<
+ "concept %0 requires more than 1 template argument; provide the remaining "
+ "arguments explicitly to use it here">;
def err_missing_dependent_template_keyword : Error<
"use 'template' keyword to treat '%0' as a dependent template name">;
Index: include/clang/AST/TemplateBase.h
===================================================================
--- include/clang/AST/TemplateBase.h
+++ include/clang/AST/TemplateBase.h
@@ -586,6 +586,10 @@
void addArgument(const TemplateArgumentLoc &Loc) {
Arguments.push_back(Loc);
}
+
+ void prependArgument(const TemplateArgumentLoc &Loc) {
+ Arguments.insert(Arguments.begin(), Loc);
+ }
};
/// \brief Represents an explicit template argument list in C++, e.g.,
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1730,9 +1730,10 @@
// D is the "T" in something like
// template <template <typename> class T> class container { };
TRY_TO(TraverseDecl(D->getTemplatedDecl()));
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
+ if (Expr *CE = D->getConstraintExpression())
+ TRY_TO(TraverseStmt(CE));
+ if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
- }
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
})
@@ -1744,6 +1745,8 @@
// D is the "T" in something like "template<typename T> class vector;"
if (D->getTypeForDecl())
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
+ if (Expr *CE = D->getConstraintExpression())
+ TRY_TO(TraverseStmt(CE));
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
})
@@ -2061,6 +2064,8 @@
DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
// A non-type template parameter, e.g. "S" in template<int S> class Foo ...
TRY_TO(TraverseDeclaratorHelper(D));
+ if (Expr *CE = D->getConstraintExpression())
+ TRY_TO(TraverseStmt(CE));
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseStmt(D->getDefaultArgument()));
})
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -82,20 +82,22 @@
/// pack.
unsigned ContainsUnexpandedParameterPack : 1;
- /// Whether this template parameter list has an associated requires-clause
- unsigned HasRequiresClause : 1;
+ /// Whether this template parameter list has associated constraints, be it a
+ /// requires clause or constrained parameters.
+ unsigned HasAssociatedConstraints : 1;
protected:
- TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
- ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc,
- Expr *RequiresClause);
+ TemplateParameterList(const ASTContext& C, SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc, ArrayRef<NamedDecl *> Params,
+ SourceLocation RAngleLoc, Expr *RequiresClause,
+ Expr *ConstrainedParamsConstraints);
size_t numTrailingObjects(OverloadToken<NamedDecl *>) const {
return NumParams;
}
size_t numTrailingObjects(OverloadToken<Expr *>) const {
- return HasRequiresClause;
+ return HasAssociatedConstraints ? 2 : 0;
}
public:
@@ -159,14 +161,29 @@
return ContainsUnexpandedParameterPack;
}
+ /// \brief Determine whether this template parameter list contains a parameter
+ /// pack.
+ bool hasParameterPack() const {
+ for (const NamedDecl *P : asArray())
+ if (P->isParameterPack())
+ return true;
+ return false;
+ }
+
/// \brief The constraint-expression of the associated requires-clause.
Expr *getRequiresClause() {
- return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr;
+ return HasAssociatedConstraints ? getTrailingObjects<Expr *>()[0] : nullptr;
}
/// \brief The constraint-expression of the associated requires-clause.
const Expr *getRequiresClause() const {
- return HasRequiresClause ? *getTrailingObjects<Expr *>() : nullptr;
+ return HasAssociatedConstraints ? getTrailingObjects<Expr *>()[0] : nullptr;
+ }
+
+ /// \brief Gets the combined constraint-expression derived from the associated
+ /// requires-clause and constrained-parameters (if any).
+ Expr *getAssociatedConstraints() const {
+ return HasAssociatedConstraints ? getTrailingObjects<Expr *>()[1] : nullptr;
}
SourceLocation getTemplateLoc() const { return TemplateLoc; }
@@ -185,25 +202,29 @@
/// \brief Stores a list of template parameters and the associated
/// requires-clause (if any) for a TemplateDecl and its derived classes.
/// Suitable for creating on the stack.
-template <size_t N, bool HasRequiresClause>
+template <size_t N, bool HasAssociatedConstraints>
class FixedSizeTemplateParameterListStorage
: public TemplateParameterList::FixedSizeStorageOwner {
typename TemplateParameterList::FixedSizeStorage<
NamedDecl *, Expr *>::with_counts<
- N, HasRequiresClause ? 1u : 0u
+ N, HasAssociatedConstraints ? 2u : 0u
>::type storage;
public:
- FixedSizeTemplateParameterListStorage(SourceLocation TemplateLoc,
+ FixedSizeTemplateParameterListStorage(const ASTContext &C,
+ SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ArrayRef<NamedDecl *> Params,
SourceLocation RAngleLoc,
- Expr *RequiresClause)
+ Expr *RequiresClause,
+ Expr *ConstrainedParamsConstraints)
: FixedSizeStorageOwner(
(assert(N == Params.size()),
- assert(HasRequiresClause == static_cast<bool>(RequiresClause)),
- new (static_cast<void *>(&storage)) TemplateParameterList(
- TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause))) {}
+ assert(HasAssociatedConstraints ==
+ (RequiresClause || ConstrainedParamsConstraints)),
+ new (static_cast<void *>(&storage)) TemplateParameterList(C,
+ TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause,
+ ConstrainedParamsConstraints))) {}
};
/// \brief A template argument list.
@@ -1131,6 +1152,10 @@
DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *>;
DefArgStorage DefaultArgument;
+ /// \brief The constraint expression introduced by this declaration (by means
+ /// of a 'constrained-parameter'.
+ Expr *ConstraintExpression = nullptr;
+
TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
bool Typename)
@@ -1207,6 +1232,18 @@
/// \brief Returns whether this is a parameter pack.
bool isParameterPack() const;
+ /// \brief Returns the constraint expression associated with this template
+ /// parameter (if any).
+ Expr *getConstraintExpression() const {
+ return ConstraintExpression;
+ }
+
+ /// \brief Sets the constraint expression associated with this template
+ /// parameter (if any).
+ void setConstraintExpression(Expr *E) {
+ ConstraintExpression = E;
+ }
+
SourceRange getSourceRange() const override LLVM_READONLY;
// Implement isa/cast/dyncast/etc.
@@ -1246,6 +1283,10 @@
/// \brief The number of types in an expanded parameter pack.
unsigned NumExpandedTypes = 0;
+ /// \brief The constraint expression introduced by this declaration (by means
+ /// of a 'constrained-parameter'.
+ Expr *ConstraintExpression = nullptr;
+
size_t numTrailingObjects(
OverloadToken<std::pair<QualType, TypeSourceInfo *>>) const {
return NumExpandedTypes;
@@ -1392,6 +1433,18 @@
return TypesAndInfos[I].second;
}
+ /// \brief Returns the constraint expression associated with this template
+ /// parameter (if any).
+ Expr *getConstraintExpression() const {
+ return ConstraintExpression;
+ }
+
+ /// \brief Sets the constraint expression associated with this template
+ /// parameter (if any).
+ void setConstraintExpression(Expr *E) {
+ ConstraintExpression = E;
+ }
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == NonTypeTemplateParm; }
@@ -1425,6 +1478,10 @@
/// \brief The number of parameters in an expanded parameter pack.
unsigned NumExpandedParams = 0;
+ /// \brief The constraint expression introduced by this declaration (by means
+ /// of a 'constrained-parameter'.
+ Expr *ConstraintExpression = nullptr;
+
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P, bool ParameterPack,
IdentifierInfo *Id, TemplateParameterList *Params)
@@ -1552,6 +1609,18 @@
/// \brief Removes the default argument of this template parameter.
void removeDefaultArgument() { DefaultArgument.clear(); }
+ /// \brief Returns the constraint expression associated with this template
+ /// parameter (if any).
+ Expr *getConstraintExpression() const {
+ return ConstraintExpression;
+ }
+
+ /// \brief Sets the constraint expression associated with this template
+ /// parameter (if any).
+ void setConstraintExpression(Expr *E) {
+ ConstraintExpression = E;
+ }
+
SourceRange getSourceRange() const override LLVM_READONLY {
SourceLocation End = getLocation();
if (hasDefaultArgument() && !defaultArgumentWasInherited())
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits