saar.raz updated this revision to Diff 138501.
saar.raz added a comment.
Adjusted to changes in https://reviews.llvm.org/D41217
Repository:
rC Clang
https://reviews.llvm.org/D41569
Files:
include/clang/AST/ExprCXX.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
include/clang/Sema/TemplateDeduction.h
lib/AST/ExprCXX.cpp
lib/Sema/SemaConcept.cpp
lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/function-templates.cpp
test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/partial-specializations.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+namespace class_templates
+{
+ template<typename T, typename U> requires sizeof(T) >= 4 // expected-note {{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
+ struct is_same { static constexpr bool value = false; };
+
+ template<typename T> requires sizeof(T*) >= 4 && sizeof(T) >= 4
+ struct is_same<T*, T*> { static constexpr bool value = true; };
+
+ static_assert(!is_same<char*, char*>::value);
+ static_assert(!is_same<short*, short*>::value);
+ static_assert(is_same<int*, int*>::value);
+ static_assert(is_same<char, char>::value); // expected-error {{constraints not satisfied for class template 'is_same' [with T = char, U = char]}}
+}
+
+namespace variable_templates
+{
+ template<typename T, typename U> requires sizeof(T) >= 4
+ constexpr bool is_same_v = false;
+
+ template<typename T> requires sizeof(T*) >= 4 && sizeof(T) >= 4
+ constexpr bool is_same_v<T*, T*> = true;
+
+ static_assert(!is_same_v<char*, char*>);
+ static_assert(!is_same_v<short*, short*>);
+ static_assert(is_same_v<int*, int*>);
+}
\ No newline at end of file
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/non-function-templates.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T> requires sizeof(T) >= 2 // expected-note{{because 'sizeof(char) >= 2' (1 >= 2) evaluated to false}}
+struct A {
+ static constexpr int value = sizeof(T);
+};
+
+static_assert(A<int>::value == 4);
+static_assert(A<char>::value == 1); // expected-error{{constraints not satisfied for class template 'A' [with T = char]}}
+
+template<typename T, typename U>
+ requires sizeof(T) != sizeof(U) // expected-note{{because 'sizeof(int) != sizeof(char [4])' (4 != 4) evaluated to false}}
+ && sizeof(T) >= 4 // expected-note{{because 'sizeof(char) >= 4' (1 >= 4) evaluated to false}}
+constexpr int SizeDiff = sizeof(T) > sizeof(U) ? sizeof(T) - sizeof(U) : sizeof(U) - sizeof(T);
+
+static_assert(SizeDiff<int, char> == 3);
+static_assert(SizeDiff<int, char[4]> == 0); // expected-error{{constraints not satisfied for variable template 'SizeDiff' [with T = int, U = char [4]]}}
+static_assert(SizeDiff<char, int> == 3); // expected-error{{constraints not satisfied for variable template 'SizeDiff' [with T = char, U = int]}}
+
+template<typename... Ts>
+ requires ((sizeof(Ts) == 4) || ...) // expected-note{{because 'sizeof(char) == 4' (1 == 4) evaluated to false}} expected-note{{'sizeof(long long) == 4' (8 == 4) evaluated to false}} expected-note{{'sizeof(int [20]) == 4' (80 == 4) evaluated to false}}
+constexpr auto SumSizes = (sizeof(Ts) + ...);
+
+static_assert(SumSizes<char, long long, int> == 13);
+static_assert(SumSizes<char, long long, int[20]> == 89); // expected-error{{constraints not satisfied for variable template 'SumSizes' [with Ts = <char, long long, int [20]>]}}
+
+template<typename T>
+concept IsBig = sizeof(T) > 100; // expected-note{{because 'sizeof(int) > 100' (4 > 100) evaluated to false}}
+
+template<typename T>
+ requires IsBig<T> // expected-note{{'int' does not satisfy 'IsBig'}}
+using BigPtr = T*;
+
+static_assert(sizeof(BigPtr<int>)); // expected-error{{constraints not satisfied for alias template 'BigPtr' [with T = int]}}}}
+
+template<typename T> requires T::value // expected-note{{because substituted constraint expression is ill-formed: type 'int' cannot be used prior to '::' because it has no members}}
+struct S { static constexpr bool value = true; };
+
+struct S2 { static constexpr bool value = true; };
+
+static_assert(S<int>::value); // expected-error{{constraints not satisfied for class template 'S' [with T = int]}}
+static_assert(S<S2>::value);
+
+template<typename T>
+struct AA
+{
+ template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
+ struct B
+ {
+ static constexpr int a = 0;
+ };
+
+ template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
+ static constexpr int b = 1;
+
+ template<typename U> requires sizeof(U) == sizeof(T) // expected-note{{because 'sizeof(int [2]) == sizeof(int)' (8 == 4) evaluated to false}}
+ static constexpr int getB() { // expected-note{{candidate template ignored: constraints not satisfied [with U = int [2]]}}
+ return 2;
+ }
+
+ static auto foo()
+ {
+ return B<T[2]>::a; // expected-error{{constraints not satisfied for class template 'B' [with U = int [2]]}}
+ }
+
+ static auto foo1()
+ {
+ return b<T[2]>; // expected-error{{constraints not satisfied for variable template 'b' [with U = int [2]]}}
+ }
+
+ static auto foo2()
+ {
+ return AA<T>::getB<T[2]>(); // expected-error{{no matching function for call to 'getB'}}
+ }
+};
+
+constexpr auto x = AA<int>::foo(); // expected-note{{in instantiation of member function 'AA<int>::foo' requested here}}
+constexpr auto x1 = AA<int>::foo1(); // expected-note{{in instantiation of member function 'AA<int>::foo1' requested here}}
+constexpr auto x2 = AA<int>::foo2(); // expected-note{{in instantiation of member function 'AA<int>::foo2' requested here}}
\ No newline at end of file
Index: test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/function-templates.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/temp/temp.constr/temp.constr.constr/function-templates.cpp
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -x c++ -verify %s
+
+template<typename T>
+constexpr bool is_ptr_v = false;
+
+template<typename T>
+constexpr bool is_ptr_v<T*> = true;
+
+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> requires is_ptr_v<T> // expected-note {{because 'is_ptr_v<int>' evaluated to false}} expected-note {{because 'is_ptr_v<char>' evaluated to false}}
+auto dereference(T t) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}} expected-note {{candidate template ignored: constraints not satisfied [with T = char]}}
+ return *t;
+}
+
+static_assert(is_same_v<decltype(dereference<int*>(nullptr)), int>);
+static_assert(is_same_v<decltype(dereference(2)), int>); // expected-error {{no matching function for call to 'dereference'}}
+static_assert(is_same_v<decltype(dereference<char>('a')), char>); // expected-error {{no matching function for call to 'dereference'}}
+
+
+template<typename T> requires T{} + T{} // expected-note {{substituted constraint expression is ill-formed: invalid operands to binary expression ('A' and 'A')}}
+auto foo(T t) { // expected-note {{candidate template ignored: constraints not satisfied [with T = A]}}
+ return t + t;
+}
+
+struct A { };
+
+static_assert(foo(A{})); // expected-error {{no matching function for call to 'foo'}}
\ No newline at end of file
Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
===================================================================
--- test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
+++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
@@ -24,9 +24,9 @@
}
};
template<typename U>
-concept C4 = U::add(1, 2) == 3;
+concept C4 = U::add(1, 2) == 3; // expected-error {{substitution into constraint expression resulted in a non-constant expression 'B::add(1, 2) == 3'}}
static_assert(C4<A>);
-static_assert(!C4<B>); // expected-error {{concept specialization 'C4<B>' resulted in a non-constant expression 'B::add(1, 2) == 3'}}
+static bool X = C4<B>; // expected-note {{in concept specialization 'C4<B>'}}
template<typename T, typename U>
constexpr bool is_same_v = false;
@@ -66,4 +66,13 @@
template<typename T> struct T2 { static constexpr bool value = sizeof(T) == 2; };
static_assert(IsTypePredicate<T2>);
-static_assert(!IsTypePredicate<T1>);
\ No newline at end of file
+static_assert(!IsTypePredicate<T1>);
+
+template<typename T, typename U, typename... Ts>
+concept OneOf = (Same<T, Ts> || ...);
+
+template<typename... X>
+constexpr bool S = OneOf<X..., int, int>;
+
+static_assert(S<int, long, int>);
+static_assert(!S<long, int, char, char>);
\ No newline at end of file
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -357,6 +357,15 @@
Record.AddTemplateArgumentLoc(TALI->getArgumentArray()[i]);
}
Record.push_back(E->isSatisfied());
+ Expr *SubstitutedExpr = E->getSubstitutedConstraintExpr();
+ Record.push_back(SubstitutedExpr != nullptr);
+ if (SubstitutedExpr) {
+ Record.AddStmt(SubstitutedExpr);
+ } else {
+ auto *SubstitutionDiagnostic = E->getSubstitutionDiagnostic();
+ Record.AddSourceLocation(SubstitutionDiagnostic->first);
+ Record.AddString(SubstitutionDiagnostic->second);
+ }
Code = serialization::EXPR_CONCEPT_SPECIALIZATION;
}
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -624,6 +624,16 @@
ArgInfo.addArgument(Record.readTemplateArgumentLoc());
E->setTemplateArguments(/*Sema=*/nullptr, &ArgInfo);
E->setSatisfied(Record.readInt() == 1);
+ if (Record.readInt()) {
+ E->setSubstitutedConstraintExpr(Record.readExpr());
+ } else {
+ SourceLocation DiagLocation = Record.readSourceLocation();
+ std::string DiagMessage = Record.readString();
+ E->setSubstitutionDiagnostic(
+ new (Record.getContext())
+ ConceptSpecializationExpr::SubstitutionDiagnostic{DiagLocation,
+ DiagMessage});
+ }
}
void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2903,12 +2903,21 @@
// Check that the template argument list is well-formed for this
// class template.
+ bool InstantiationDependent;
SmallVector<TemplateArgument, 4> Converted;
if (SemaRef.CheckTemplateArgumentList(InstClassTemplate,
D->getLocation(),
InstTemplateArgs,
false,
- Converted))
+ Converted,
+ /*UpdateArgsWithConversion=*/true,
+ &InstantiationDependent))
+ return nullptr;
+
+ if (!InstantiationDependent
+ && SemaRef.EnsureTemplateArgumentListConstraints(InstClassTemplate,
+ Converted,
+ D->getLocation()))
return nullptr;
// Figure out where to insert this class template explicit specialization
@@ -3025,11 +3034,18 @@
return nullptr;
// Check that the template argument list is well-formed for this template.
+ bool InstantiationDependent;
SmallVector<TemplateArgument, 4> Converted;
if (SemaRef.CheckTemplateArgumentList(
VarTemplate, VarTemplate->getLocStart(),
const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false,
- Converted))
+ Converted, /*UpdateArgsWithConversion=*/true,
+ &InstantiationDependent))
+ return nullptr;
+
+ if (!InstantiationDependent
+ && SemaRef.EnsureTemplateArgumentListConstraints(VarTemplate, Converted,
+ VarTemplate->getLocStart()))
return nullptr;
// Find the variable template specialization declaration that
Index: lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- lib/Sema/SemaTemplateDeduction.cpp
+++ lib/Sema/SemaTemplateDeduction.cpp
@@ -2658,6 +2658,27 @@
return Sema::TDK_Success;
}
+template<typename TemplateDeclT>
+static Sema::TemplateDeductionResult
+CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template,
+ ArrayRef<TemplateArgument> DeducedArgs,
+ TemplateDeductionInfo& Info) {
+ bool IsSatisfied = false;
+ ExprResult SubstitutedExpr;
+ llvm::Optional<PartialDiagnosticAt> SubstDiag;
+ if (S.CheckConstraintSatisfaction(Template,
+ Template->getAssociatedConstraints(),
+ DeducedArgs, Info.getLocation(),
+ IsSatisfied, SubstitutedExpr, SubstDiag)
+ || !IsSatisfied) {
+ if (SubstDiag)
+ Info.addSFINAEDiagnostic(SubstDiag->first, SubstDiag->second);
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs));
+ Info.SubstitutedConstraintExpr = SubstitutedExpr;
+ return Sema::TDK_ConstraintsNotSatisfied;
+ }
+ return Sema::TDK_Success;
+}
/// \brief Perform template argument deduction to determine whether
/// the given template arguments match the given class template
@@ -2698,6 +2719,10 @@
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
+ if (TemplateDeductionResult Result
+ = CheckDeducedArgumentConstraints(*this, Partial, DeducedArgs, Info))
+ return Result;
+
return ::FinishTemplateArgumentDeduction(
*this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info);
}
@@ -2739,6 +2764,10 @@
if (Trap.hasErrorOccurred())
return Sema::TDK_SubstitutionFailure;
+ if (TemplateDeductionResult Result
+ = CheckDeducedArgumentConstraints(*this, Partial, DeducedArgs, Info))
+ return Result;
+
return ::FinishTemplateArgumentDeduction(
*this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info);
}
@@ -2848,6 +2877,12 @@
= TemplateArgumentList::CreateCopy(Context, Builder);
Info.reset(ExplicitArgumentList);
+ if (TemplateDeductionResult Result
+ = CheckDeducedArgumentConstraints(*this, FunctionTemplate,
+ ExplicitArgumentList->asArray(),
+ Info))
+ return Result;
+
// Template argument deduction and the final substitution should be
// done in the context of the templated declaration. Explicit
// argument substitution, on the other hand, needs to happen in the
@@ -3155,6 +3190,11 @@
PartialOverloading))
return Result;
+ if (TemplateDeductionResult Result
+ = CheckDeducedArgumentConstraints(*this, FunctionTemplate, DeducedArgs,
+ Info))
+ return Result;
+
// C++ [temp.deduct.call]p10: [DR1391]
// If deduction succeeds for all parameters that contain
// template-parameters that participate in template argument deduction,
@@ -4911,6 +4951,7 @@
static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
TemplateLikeDecl *P2,
TemplateDeductionInfo &Info) {
+ // TODO: Concepts: Regard constraints
// C++ [temp.class.order]p1:
// For two class template partial specializations, the first is at least as
// specialized as the second if, given the following rewrite to two
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -2892,8 +2892,7 @@
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template) ||
- isa<VarTemplateDecl>(Template) ||
- isa<ConceptDecl>(Template)) {
+ isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
@@ -2907,16 +2906,25 @@
// Check that the template argument list is well-formed for this
// template.
+ bool InstantiationDependentMatch;
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs,
- false, Converted))
+ false, Converted,
+ /*UpdateArgsWithConversion=*/true,
+ &InstantiationDependentMatch))
+ return QualType();
+
+ if (!InstantiationDependentMatch
+ && EnsureTemplateArgumentListConstraints(Template, Converted,
+ TemplateLoc))
return QualType();
QualType CanonType;
bool InstantiationDependent = false;
if (TypeAliasTemplateDecl *AliasTemplate =
dyn_cast<TypeAliasTemplateDecl>(Template)) {
+
// Find the canonical type for this type alias template specialization.
TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl();
if (Pattern->isInvalidDecl())
@@ -3502,9 +3510,17 @@
// Check that the template argument list is well-formed for this
// template.
+ bool InstantiationDependent;
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs,
- false, Converted))
+ false, Converted,
+ /*UpdateArgsWithConversion=*/true,
+ &InstantiationDependent))
+ return true;
+
+ if (!InstantiationDependent
+ && EnsureTemplateArgumentListConstraints(VarTemplate, Converted,
+ TemplateNameLoc))
return true;
// Find the variable template (partial) specialization declaration that
@@ -3678,11 +3694,18 @@
assert(Template && "A variable template id without template?");
// Check that the template argument list is well-formed for this template.
+ bool InstantiationDependentMatch;
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(
Template, TemplateNameLoc,
const_cast<TemplateArgumentListInfo &>(TemplateArgs), false,
- Converted))
+ Converted, /*UpdateArgsWithConversion=*/true,
+ &InstantiationDependentMatch))
+ return true;
+
+ if (!InstantiationDependentMatch
+ && EnsureTemplateArgumentListConstraints(Template, Converted,
+ TemplateNameLoc))
return true;
// Find the variable template specialization declaration that
@@ -3896,7 +3919,7 @@
TemplateKWLoc, TemplateArgs);
}
- if (R.getAsSingle<ConceptDecl>() && !DependentArguments) {
+ if (R.getAsSingle<ConceptDecl>()) {
return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
R.getAsSingle<ConceptDecl>(),
TemplateKWLoc, TemplateArgs);
@@ -4788,7 +4811,8 @@
TemplateDecl *Template, SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs,
SmallVectorImpl<TemplateArgument> &Converted,
- bool UpdateArgsWithConversions) {
+ bool UpdateArgsWithConversions, bool *InstantiationDependent) {
+
// Make a copy of the template arguments for processing. Only make the
// changes at the end when successful in matching the arguments to the
// template.
@@ -4892,6 +4916,10 @@
++ArgIdx;
}
+ // We cannot determine yet whether the arguments are well-formed.
+ if (InstantiationDependent)
+ *InstantiationDependent = true;
+
return false;
}
@@ -4904,6 +4932,8 @@
Converted.push_back(
TemplateArgument::CreatePackCopy(Context, ArgumentPack));
+ if (InstantiationDependent)
+ *InstantiationDependent = false;
return false;
}
@@ -5034,6 +5064,9 @@
if (UpdateArgsWithConversions)
TemplateArgs = std::move(NewArgs);
+ if (InstantiationDependent)
+ *InstantiationDependent = false;
+
return false;
}
@@ -7397,9 +7430,17 @@
// Check that the template argument list is well-formed for this
// template.
+ bool InstantiationDependent;
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted))
+ TemplateArgs, false, Converted,
+ /*UpdateArgsWithConversion=*/true,
+ &InstantiationDependent))
+ return true;
+
+ if (!InstantiationDependent
+ && EnsureTemplateArgumentListConstraints(ClassTemplate, Converted,
+ TemplateNameLoc))
return true;
// Find the class template (partial) specialization declaration that
@@ -8573,10 +8614,19 @@
// Check that the template argument list is well-formed for this
// template.
+ bool InstantiationDependent;
SmallVector<TemplateArgument, 4> Converted;
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc,
- TemplateArgs, false, Converted))
+ TemplateArgs, false, Converted,
+ /*UpdateArgsWithConversion=*/true,
+ &InstantiationDependent))
+ return true;
+
+ if (!InstantiationDependent
+ && EnsureTemplateArgumentListConstraints(ClassTemplate, Converted,
+ TemplateNameLoc)) {
return true;
+ }
// Find the class template specialization declaration that
// corresponds to these arguments.
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp
+++ lib/Sema/SemaOverload.cpp
@@ -578,6 +578,10 @@
TemplateArgumentList *TemplateArgs;
unsigned CallArgIndex;
};
+ struct CNSInfo {
+ TemplateArgumentList *TemplateArgs;
+ ExprResult SubstitutedConstraintExpr;
+ };
}
/// \brief Convert from Sema's representation of template deduction information
@@ -646,6 +650,21 @@
}
break;
+ case Sema::TDK_ConstraintsNotSatisfied: {
+ CNSInfo *Saved = new (Context) CNSInfo;
+ Saved->TemplateArgs = Info.take();
+ Saved->SubstitutedConstraintExpr = Info.SubstitutedConstraintExpr;
+ Result.Data = Saved;
+
+ if (Info.hasSFINAEDiagnostic()) {
+ PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt(
+ SourceLocation(), PartialDiagnostic::NullDiagnostic());
+ Info.takeSFINAEDiagnostic(*Diag);
+ Result.HasDiagnostic = true;
+ }
+ break;
+ }
+
case Sema::TDK_Success:
case Sema::TDK_NonDependentConversionFailure:
llvm_unreachable("not a deduction failure");
@@ -685,6 +704,15 @@
}
break;
+ case Sema::TDK_ConstraintsNotSatisfied:
+ // FIXME: Destroy the template argument list?
+ Data = nullptr;
+ if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) {
+ Diag->~PartialDiagnosticAt();
+ HasDiagnostic = false;
+ }
+ break;
+
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
break;
@@ -710,6 +738,7 @@
case Sema::TDK_NonDeducedMismatch:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return TemplateParameter();
case Sema::TDK_Incomplete:
@@ -751,6 +780,9 @@
case Sema::TDK_SubstitutionFailure:
return static_cast<TemplateArgumentList*>(Data);
+ case Sema::TDK_ConstraintsNotSatisfied:
+ return static_cast<CNSInfo*>(Data)->TemplateArgs;
+
// Unhandled
case Sema::TDK_MiscellaneousDeductionFailure:
break;
@@ -771,6 +803,7 @@
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -800,6 +833,7 @@
case Sema::TDK_SubstitutionFailure:
case Sema::TDK_CUDATargetMismatch:
case Sema::TDK_NonDependentConversionFailure:
+ case Sema::TDK_ConstraintsNotSatisfied:
return nullptr;
case Sema::TDK_Inconsistent:
@@ -1178,6 +1212,8 @@
return NewTarget != OldTarget;
}
+ // TODO: Concepts: Check function trailing requires clauses here.
+
// The signatures match; this is not an overload.
return false;
}
@@ -9865,6 +9901,27 @@
MaybeEmitInheritedConstructorNote(S, Found);
return;
+ case Sema::TDK_ConstraintsNotSatisfied: {
+ // Format the template argument list into the argument string.
+ SmallString<128> TemplateArgString;
+ TemplateArgumentList *Args = DeductionFailure.getTemplateArgumentList();
+ TemplateArgString = " ";
+ TemplateArgString += S.getTemplateArgumentBindingsText(
+ getDescribedTemplate(Templated)->getTemplateParameters(), *Args);
+ S.Diag(Templated->getLocation(),
+ diag::note_ovl_candidate_unsatisfied_constraints)
+ << TemplateArgString;
+
+ if (DeductionFailure.HasDiagnostic) {
+ S.DiagnoseUnsatisfiedIllFormedConstraint(
+ DeductionFailure.getSFINAEDiagnostic());
+ } else {
+ S.DiagnoseUnsatisfiedConstraint(
+ static_cast<CNSInfo*>(DeductionFailure.Data)
+ ->SubstitutedConstraintExpr.get());
+ }
+ return;
+ }
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
DiagnoseArityMismatch(S, Found, Templated, NumArgs);
@@ -10271,15 +10328,18 @@
case Sema::TDK_CUDATargetMismatch:
return 3;
- case Sema::TDK_InstantiationDepth:
+ case Sema::TDK_ConstraintsNotSatisfied:
return 4;
- case Sema::TDK_InvalidExplicitArguments:
+ case Sema::TDK_InstantiationDepth:
return 5;
+ case Sema::TDK_InvalidExplicitArguments:
+ return 6;
+
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
- return 6;
+ return 7;
}
llvm_unreachable("Unhandled deduction result");
}
Index: lib/Sema/SemaConcept.cpp
===================================================================
--- lib/Sema/SemaConcept.cpp
+++ lib/Sema/SemaConcept.cpp
@@ -11,7 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/TemplateDeduction.h"
+#include "clang/Sema/Template.h"
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ExprCXX.h"
using namespace clang;
using namespace sema;
@@ -55,4 +58,245 @@
return true; // All good; no mismatch.
}
return false;
+}
+
+template<typename TemplateDeclT>
+bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template,
+ const Expr *ConstraintExpr,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc,
+ bool &IsSatisfied,
+ ExprResult &SubstitutedExpression,
+ llvm::Optional<PartialDiagnosticAt>& SubstDiag) {
+ if (!ConstraintExpr) {
+ IsSatisfied = true;
+ SubstitutedExpression.set(nullptr);
+ return false;
+ }
+
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(TemplateArgs);
+
+ {
+ // We do not want error diagnostics escaping here.
+ TemplateDeductionInfo Info(TemplateNameLoc);
+ Sema::InstantiatingTemplate Inst(S, TemplateNameLoc, Template, TemplateArgs,
+ Info);
+ Sema::SFINAETrap Trap(S);
+
+ SubstitutedExpression = S.SubstExpr(const_cast<Expr*>(ConstraintExpr),
+ MLTAL);
+ if (SubstitutedExpression.isInvalid() || !SubstitutedExpression.isUsable()
+ || Trap.hasErrorOccurred()) {
+ // C++2a [temp.constr.atomic]p1
+ // ...If substitution results in an invalid type or expression, the
+ // constraint is not satisfied.
+ if (Trap.hasErrorOccurred()) {
+ SubstDiag = PartialDiagnosticAt{ SourceLocation(),
+ PartialDiagnostic::NullDiagnostic() };
+ Info.takeSFINAEDiagnostic(SubstDiag.getValue());
+ }
+ IsSatisfied = false;
+ return false;
+ }
+ }
+
+ if (!S.CheckConstraintExpression(SubstitutedExpression.get())) {
+ return true;
+ }
+
+ if (SubstitutedExpression.get()->isInstantiationDependent()) {
+ IsSatisfied = true;
+ return false;
+ }
+
+ bool Satisfied = false;
+ if (!SubstitutedExpression.get()->EvaluateAsBooleanCondition(Satisfied,
+ S.Context)) {
+ // C++2a [temp.constr.atomic]p1
+ // ...E shall be a constant expression of type bool.
+ S.Diag(ConstraintExpr->getLocStart(),
+ diag::err_concept_non_constant_constraint_expression)
+ << SubstitutedExpression.get();
+ return true;
+ }
+ IsSatisfied = Satisfied;
+ return false;
+}
+
+bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template,
+ const Expr *ConstraintExpr,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc,
+ bool &IsSatisfied,
+ ExprResult &SubstitutedExpression,
+ llvm::Optional<PartialDiagnosticAt>& SubstDiag) {
+ return ::CheckConstraintSatisfaction(*this, Template, ConstraintExpr,
+ TemplateArgs, TemplateNameLoc,
+ IsSatisfied, SubstitutedExpression,
+ SubstDiag);
+}
+
+bool
+Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part,
+ const Expr *ConstraintExpr,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc,
+ bool &IsSatisfied,
+ ExprResult &SubstitutedExpression,
+ llvm::Optional<PartialDiagnosticAt>& SubstDiag) {
+ return ::CheckConstraintSatisfaction(*this, Part, ConstraintExpr,
+ TemplateArgs, TemplateNameLoc,
+ IsSatisfied, SubstitutedExpression,
+ SubstDiag);
+}
+
+bool
+Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial,
+ const Expr *ConstraintExpr,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc,
+ bool &IsSatisfied,
+ ExprResult &SubstitutedExpression,
+ llvm::Optional<PartialDiagnosticAt>& SubstDiag) {
+ return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExpr,
+ TemplateArgs, TemplateNameLoc,
+ IsSatisfied, SubstitutedExpression,
+ SubstDiag);
+}
+
+bool Sema::EnsureTemplateArgumentListConstraints(TemplateDecl *TD,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc) {
+ bool IsSatisfied;
+ ExprResult SubstitutedConstraintExpr;
+ llvm::Optional<PartialDiagnosticAt> SubstDiag;
+ if (CheckConstraintSatisfaction(TD, TD->getAssociatedConstraints(),
+ TemplateArgs, TemplateNameLoc, IsSatisfied,
+ SubstitutedConstraintExpr, SubstDiag))
+ return true;
+
+ if (!IsSatisfied) {
+ SmallString<128> TemplateArgString;
+ TemplateArgString = " ";
+ TemplateArgString += getTemplateArgumentBindingsText(
+ TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size());
+
+ Diag(TemplateNameLoc, diag::err_template_arg_list_constraints_not_satisfied)
+ << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD
+ << TemplateArgString;
+ if (SubstitutedConstraintExpr.isUsable()) {
+ DiagnoseUnsatisfiedConstraint(SubstitutedConstraintExpr.get());
+ } else {
+ DiagnoseUnsatisfiedIllFormedConstraint(SubstDiag.getPointer());
+ }
+ return true;
+ }
+ return false;
+}
+
+static void diagnoseUnsatisfiedConstraintExpr(Sema &S, Expr *E,
+ bool First = true) {
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ switch(BO->getOpcode()) {
+ case BO_LAnd: {
+ // Either LHS or RHS evaluated to false.
+ bool Result = false;
+ BO->getLHS()->EvaluateAsBooleanCondition(Result, S.Context);
+ if (Result) {
+ // LHS evaluated to true - therefore RHS evaluated to false.
+ diagnoseUnsatisfiedConstraintExpr(S, BO->getRHS(), First);
+ return;
+ }
+ // LHS evaluated to false - diagnose it.
+ diagnoseUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
+ BO->getRHS()->EvaluateAsBooleanCondition(Result, S.Context);
+ if (!Result) {
+ // RHS evaluated to false as well - diagnose it too.
+ diagnoseUnsatisfiedConstraintExpr(S, BO->getRHS(), /*First=*/false);
+ }
+ return;
+ }
+
+ case BO_LOr:
+ // Both LHS and RHS evaluated to false.
+ diagnoseUnsatisfiedConstraintExpr(S, BO->getLHS(), First);
+ diagnoseUnsatisfiedConstraintExpr(S, BO->getRHS(), /*First=*/false);
+ return;
+
+ case BO_GE:
+ case BO_LE:
+ case BO_GT:
+ case BO_LT:
+ case BO_EQ:
+ case BO_NE:
+ if (BO->getLHS()->getType()->isIntegerType() &&
+ BO->getRHS()->getType()->isIntegerType()) {
+ llvm::APSInt SimplifiedLHS;
+ llvm::APSInt SimplifiedRHS;
+ BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context);
+ BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context);
+ S.Diag(E->getSourceRange().getBegin(),
+ diag::note_atomic_constraint_evaluated_to_false_elaborated)
+ << (int) First << E << SimplifiedLHS.toString(10)
+ << BinaryOperator::getOpcodeStr(BO->getOpcode())
+ << SimplifiedRHS.toString(10);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ } else if (ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
+ diagnoseUnsatisfiedConstraintExpr(S, PE->getSubExpr(), First);
+ return;
+ } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(E)) {
+ if (CSE->getTemplateArgumentListInfo()->size() == 1) {
+ S.Diag(E->getSourceRange().getBegin(),
+ diag::note_single_arg_concept_specialization_constraint_evaluated_to_false)
+ << (int)First
+ << CSE->getTemplateArgumentListInfo()->arguments()[0].getArgument()
+ << CSE->getSpecializedConcept();
+ } else {
+ S.Diag(E->getSourceRange().getBegin(),
+ diag::note_concept_specialization_constraint_evaluated_to_false)
+ << (int)First << E;
+ }
+ if (Expr *Subst = CSE->getSubstitutedConstraintExpr()) {
+ S.DiagnoseUnsatisfiedConstraint(Subst);
+ } else {
+ auto *Diag = CSE->getSubstitutionDiagnostic();
+ assert(Diag && "Unsatisfied constraint expression with no substituted "
+ "expr nor diagnostic - is it still dependent?");
+ S.DiagnoseUnsatisfiedIllFormedConstraint(Diag->first, Diag->second);
+ }
+ return;
+ }
+ S.Diag(E->getSourceRange().getBegin(),
+ diag::note_atomic_constraint_evaluated_to_false) << (int)First << E;
+}
+
+void Sema::DiagnoseUnsatisfiedConstraint(Expr *UnsatisfiedConstraintExpr) {
+ diagnoseUnsatisfiedConstraintExpr(*this, UnsatisfiedConstraintExpr);
+}
+
+void Sema::DiagnoseUnsatisfiedIllFormedConstraint(PartialDiagnosticAt *PDiag) {
+ if (PDiag) {
+ SmallString<128> SFINAEArgString;
+ SFINAEArgString = ": ";
+ PDiag->second.EmitToString(getDiagnostics(), SFINAEArgString);
+ DiagnoseUnsatisfiedIllFormedConstraint(PDiag->first, SFINAEArgString);
+ } else {
+ DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation(), "");
+ }
+}
+void Sema::DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLoc,
+ StringRef Diagnostic) {
+ Diag(DiagnosticLoc,
+ diag::note_substituted_constraint_expr_is_ill_formed)
+ << Diagnostic;
}
\ No newline at end of file
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -1453,55 +1453,6 @@
EmptyShell Empty)
: Expr(ConceptSpecializationExprClass, Empty) { }
-bool ConceptSpecializationExpr::calculateSatisfaction(Sema &S)
-{
- llvm::SmallVector<TemplateArgument, 4> Converted;
- if (S.CheckTemplateArgumentList(NamedConcept, NamedConcept->getLocStart(),
- TemplateArgInfo,
- /*PartialTemplateArgs=*/false, Converted,
- /*UpdateArgsWithConversion=*/false)) {
- // We converted these arguments back in CheckConceptTemplateId, this should
- // work.
- return true;
- }
- EnterExpressionEvaluationContext ConstantEvaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
-
-
- MultiLevelTemplateArgumentList MLTAL;
- MLTAL.addOuterTemplateArguments(Converted);
-
- ExprResult E;
- {
- // We do not want error diagnostics escaping here.
- Sema::SFINAETrap Trap(S);
- E = S.SubstExpr(NamedConcept->getConstraintExpr(), MLTAL);
- if (E.isInvalid() || Trap.hasErrorOccurred()) {
- // C++2a [temp.constr.atomic]p1
- // ...If substitution results in an invalid type or expression, the
- // constraint is not satisfied.
- IsSatisfied = false;
- return true;
- }
- }
-
- if (!S.CheckConstraintExpression(E.get())) {
- S.Diag(getLocStart(), diag::note_in_concept_specialization) << this;
- return true;
- }
-
- bool Satisfied = false;
- if (!E.get()->EvaluateAsBooleanCondition(Satisfied, S.Context)) {
- // C++2a [temp.constr.atomic]p1
- // ...E shall be a constant expression of type bool.
- S.Diag(getLocStart(), diag::err_concept_non_constant_constraint_expression)
- << this << E.get();
- return true;
- }
- IsSatisfied = Satisfied;
- return false;
-}
-
bool ConceptSpecializationExpr::setTemplateArguments(Sema *S,
const TemplateArgumentListInfo *TALI){
bool IsDependent = false;
@@ -1524,8 +1475,48 @@
setValueDependent(IsDependent);
setInstantiationDependent(IsDependent);
setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
- if (!IsDependent && S) {
- return calculateSatisfaction(*S);
+ if (!S)
+ // The expression is probably being read from a module file.
+ return false;
+
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ bool InstantiationDependent = false;
+ if (S->CheckTemplateArgumentList(SpecializedConcept,
+ SpecializedConcept->getLocStart(),
+ TemplateArgInfo,
+ /*PartialTemplateArgs=*/false, Converted,
+ /*UpdateArgsWithConversion=*/false,
+ &InstantiationDependent))
+ // We converted these arguments back in CheckConceptTemplateId, this should
+ // work.
+ return true;
+
+ if (InstantiationDependent) {
+ // We can't instantiate the constraint expression now.
+ IsSatisfied = true;
+ return false;
+ }
+
+ ExprResult SubstConstraint;
+ llvm::Optional<PartialDiagnosticAt> SubstDiagnostic;
+ if (S->CheckConstraintSatisfaction(SpecializedConcept,
+ SpecializedConcept->getConstraintExpr(),
+ Converted, ConceptNameLoc, IsSatisfied,
+ SubstConstraint, SubstDiagnostic)){
+ S->Diag(getLocStart(), diag::note_in_concept_specialization) << this;
+ return true;
+ }
+ if (!SubstConstraint.isInvalid() && SubstConstraint.isUsable())
+ SubstitutedConstraintExpr = SubstConstraint.get();
+ else if (SubstDiagnostic.hasValue()) {
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ SubstDiagnostic.getValue().second.EmitToString(S->getDiagnostics(),
+ DiagString);
+ SubstitutedConstraintExpr =
+ new (S->Context) SubstitutionDiagnostic{
+ SubstDiagnostic.getValue().first, std::string(DiagString.begin(),
+ DiagString.end()) };
}
return false;
}
\ No newline at end of file
Index: include/clang/Sema/TemplateDeduction.h
===================================================================
--- include/clang/Sema/TemplateDeduction.h
+++ include/clang/Sema/TemplateDeduction.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
#define LLVM_CLANG_SEMA_TEMPLATEDEDUCTION_H
+#include "clang/Sema/Ownership.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallVector.h"
@@ -192,6 +193,10 @@
///
/// FIXME: This should be kept internal to SemaTemplateDeduction.
SmallVector<DeducedPack *, 8> PendingDeducedPacks;
+
+ /// \brief The substituted constraint expression used to determine whether the
+ /// associated constraints were satisfied.
+ ExprResult SubstitutedConstraintExpr;
};
} // end namespace sema
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5577,15 +5577,78 @@
ConceptDecl *CD,
const TemplateArgumentListInfo *TALI);
- /// Check whether the given expression is a valid constraint expression.
- /// A diagnostic is emitted if it is not, and false is returned.
+ /// \brief Check whether the given expression is a valid constraint
+ /// expression. A diagnostic is emitted if it is not, and false is returned.
bool CheckConstraintExpression(Expr *CE);
+ /// \brief Check whether the given constraint expression is satisfied given
+ /// template arguments. Returns false and updates IsSatisfied with the
+ /// satisfaction verdict if successful, emits a diagnostic and returns true if
+ /// an error occured and satisfaction could not be determined.
+ ///
+ /// \param SubstitutedExpr if not null, will be used to return the substituted
+ /// constraint expression (to be used for diagnostics, for example).
+ ///
+ /// \param SubstDiag if the constraint was not satisfied because of a
+ /// substitution failure, this will contain the emitted diagnostics, if any.
+ ///
+ /// \returns true if an error occurred, false otherwise.
+ bool CheckConstraintSatisfaction(TemplateDecl *Template,
+ const Expr *ConstraintExpr,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc,
+ bool &IsSatisfied,
+ ExprResult &SubstitutedExpression,
+ llvm::Optional<PartialDiagnosticAt>& SubstDiag);
+
+ bool CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl *TD,
+ const Expr *ConstraintExpr,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc,
+ bool &IsSatisfied,
+ ExprResult &SubstitutedExpression,
+ llvm::Optional<PartialDiagnosticAt>& SubstDiag);
+
+ bool CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl *TD,
+ const Expr *ConstraintExpr,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc,
+ bool &IsSatisfied,
+ ExprResult &SubstitutedExpression,
+ llvm::Optional<PartialDiagnosticAt>& SubstDiag);
+
/// \brief Check that the associated constraints of a template declaration
/// match the associated constraints of an older declaration of which it is a
/// redeclaration
bool CheckRedeclarationConstraintMatch(const Expr *OldAC, const Expr *NewAC);
+ /// \brief Ensure that the given template arguments satisfy the constraints
+ /// associated with the given template, emitting a diagnostic if they do not.
+ ///
+ /// \param Template The template to which the template arguments are being
+ /// provided.
+ ///
+ /// \param TemplateArgs The converted, canonicalized template arguments.
+ ///
+ /// \param TemplateNameLoc Where was the template name that evoked this
+ /// constraints check.
+ ///
+ /// \returns true if the constrains are not satisfied or could not be checked
+ /// for satisfaction, false if the constraints are satisfied.
+ bool EnsureTemplateArgumentListConstraints(TemplateDecl *Template,
+ ArrayRef<TemplateArgument> TemplateArgs,
+ SourceLocation TemplateNameLoc);
+
+ /// \brief Emit diagnostics explaining why a constraint expression was deemed
+ /// unsatisfied.
+ void DiagnoseUnsatisfiedConstraint(Expr *SubstitutedConstraintExpr);
+
+ /// \brief Emit diagnostics explaining why a constraint expression was deemed
+ /// unsatisfied because it was ill-formed.
+ void DiagnoseUnsatisfiedIllFormedConstraint(SourceLocation DiagnosticLocation,
+ StringRef Diagnostic);
+ void DiagnoseUnsatisfiedIllFormedConstraint(PartialDiagnosticAt *Diagnostic);
+
// ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ArrayRef<Expr *> Strings);
@@ -6352,13 +6415,19 @@
/// contain the converted forms of the template arguments as written.
/// Otherwise, \p TemplateArgs will not be modified.
///
+ /// \param InstantiationDependent If provided, and no error occured, will
+ /// receive true if the arguments' match to the given template is
+ /// instantiation dependant - e.g. the arguments contain a pack expansion
+ /// into a non pack parameter.
+ ///
/// \returns true if an error occurred, false otherwise.
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs,
bool PartialTemplateArgs,
SmallVectorImpl<TemplateArgument> &Converted,
- bool UpdateArgsWithConversions = true);
+ bool UpdateArgsWithConversions = true,
+ bool *InstantiationDependent = nullptr);
bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
TemplateArgumentLoc &Arg,
@@ -6900,6 +6969,9 @@
TDK_InvalidExplicitArguments,
/// \brief Checking non-dependent argument conversions failed.
TDK_NonDependentConversionFailure,
+ /// \brief The deduced arguments did not satisfy the constraints associated
+ /// with the template.
+ TDK_ConstraintsNotSatisfied,
/// \brief Deduction failed; that's all we know.
TDK_MiscellaneousDeductionFailure,
/// \brief CUDA Target attributes do not match.
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2402,11 +2402,31 @@
def err_concept_no_associated_constraints : Error<
"concept may not have associated constraints">;
def err_concept_non_constant_constraint_expression : Error<
- "concept specialization '%0' resulted in a non-constant expression '%1'">;
+ "substitution into constraint expression resulted in a non-constant expression '%0'">;
def err_non_bool_atomic_constraint : Error<
"atomic constraint '%0' must be of type 'bool' (found %1)">;
def note_in_concept_specialization : Note<
"in concept specialization '%0'">;
+def err_template_arg_list_constraints_not_satisfied : Error<
+ "constraints not satisfied for %select{class template|function template|variable template|alias template|"
+ "template template parameter|template}0 %1%2">;
+def note_constraints_not_satisfied : Note<
+ "constraints not satisfied">;
+def note_substituted_constraint_expr_is_ill_formed : Note<
+ "because substituted constraint expression is ill-formed%0">;
+def note_atomic_constraint_evaluated_to_false : Note<
+ "%select{and |because }0'%1' evaluated to false">;
+def note_concept_specialization_constraint_evaluated_to_false : Note<
+ "%select{and |because }0'%1' evaluated to false">;
+def note_single_arg_concept_specialization_constraint_evaluated_to_false : Note<
+ "%select{and |because }0%1 does not satisfy %2">;
+def note_atomic_constraint_evaluated_to_false_elaborated : Note<
+ "%select{and |because }0'%1' (%2 %3 %4) evaluated to false">;
+def err_could_not_normalize_ill_formed_constraint : Error<
+ "required expansion of concept specialization %0 failed, substituted "
+ "expression would be illegal">;
+def note_could_not_normalize_ill_formed_constraint_reason : Note<
+ "because: %0">;
def err_template_different_associated_constraints : Error<
"associated constraints differ in template redeclaration">;
@@ -3540,6 +3560,8 @@
def note_ovl_candidate_explicit_arg_mismatch_named : Note<
"candidate template ignored: invalid explicitly-specified argument "
"for template parameter %0">;
+def note_ovl_candidate_unsatisfied_constraints : Note<
+ "candidate template ignored: constraints not satisfied%0">;
def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note<
"candidate template ignored: invalid explicitly-specified argument "
"for %ordinal0 template parameter">;
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -4415,6 +4415,9 @@
/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
/// specialization of a concept results in a prvalue of type bool.
class ConceptSpecializationExpr final : public Expr {
+public:
+ using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
+
protected:
/// \brief The concept named.
ConceptDecl *NamedConcept;
@@ -4430,12 +4433,18 @@
/// when the expression was created. If any of the template arguments are
/// dependent (this expr would then be isValueDependent()), this is to be
/// ignored.
- bool IsSatisfied : 1;
+ bool IsSatisfied;
- /// \brief Evaluates this concept specialization to determine whether or not
- /// the concept is satisfied, and updates the IsSatisfied field. Returns true
- /// if an error occured and the concept could not be checked for satisfaction.
- bool calculateSatisfaction(Sema &S);
+ /// \brief The concept's constraint expression with the template arguments
+ /// substituted in for use in diagnostics and normalization. If the
+ /// substituted expression was ill-formed, this will store diagnostic
+ /// explaining why it was so. If the template arguments could not be
+ /// substituted into the constraint expression, this will be null.
+ ///
+ /// This may still contain a substituted constraint exception even if the
+ /// expression is dependent (but this is not always the case).
+ llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>
+ SubstitutedConstraintExpr;
public:
ConceptSpecializationExpr(ASTContext &C, Sema &S,
@@ -4479,8 +4488,24 @@
IsSatisfied = Satisfied;
}
+ Expr *getSubstitutedConstraintExpr() const {
+ return SubstitutedConstraintExpr.dyn_cast<Expr *>();
+ }
+
+ void setSubstitutedConstraintExpr(Expr *SCE) {
+ SubstitutedConstraintExpr = SCE;
+ }
+
+ const SubstitutionDiagnostic *getSubstitutionDiagnostic() const {
+ return SubstitutedConstraintExpr.dyn_cast<SubstitutionDiagnostic*>();
+ }
+
+ void setSubstitutionDiagnostic(SubstitutionDiagnostic *Diag) {
+ SubstitutedConstraintExpr = Diag;
+ }
+
SourceLocation getConceptNameLoc() const { return ConceptNameLoc; }
- void setConceptNameLoc(SourceLocation Loc) {
+ void setConceptNameLoc(SourceLocation Loc) {
ConceptNameLoc = Loc;
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits