Revert "[clang] Instantiate concepts with sugared template arguments"
This reverts commit b8064374b2.
Based on the report here:
https://github.com/llvm/llvm-project/issues/59271
this produces a significant increase in memory use of the compiler and a
large compile-time regression. This patch reverts this so that we don't
branch for release with that issue.
This commit is contained in:
@@ -1141,7 +1141,7 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
|
||||
TemplateArgumentList TAL{TemplateArgumentList::OnStack,
|
||||
CSE->getTemplateArguments()};
|
||||
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
|
||||
CSE->getNamedConcept(), /*Final=*/true, &TAL,
|
||||
CSE->getNamedConcept(), /*Final=*/false, &TAL,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConstraintInstantiation=*/true);
|
||||
|
||||
@@ -1482,57 +1482,53 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
|
||||
// C++2b:
|
||||
// Otherwise, if the type contains a placeholder type, it is replaced by the
|
||||
// type determined by placeholder type deduction.
|
||||
if (const DeducedType *Deduced = Ty->getContainedDeducedType();
|
||||
Deduced && !Deduced->isDeduced()) {
|
||||
if (isa<DeducedTemplateSpecializationType>(Deduced)) {
|
||||
Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity, Kind,
|
||||
Exprs);
|
||||
if (Ty.isNull())
|
||||
return ExprError();
|
||||
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
|
||||
} else {
|
||||
assert(isa<AutoType>(Deduced));
|
||||
MultiExprArg Inits = Exprs;
|
||||
if (ListInitialization) {
|
||||
auto *ILE = cast<InitListExpr>(Exprs[0]);
|
||||
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
|
||||
}
|
||||
|
||||
if (Inits.empty())
|
||||
return ExprError(
|
||||
Diag(TyBeginLoc, diag::err_auto_expr_init_no_expression)
|
||||
<< Ty << FullRange);
|
||||
if (Inits.size() > 1) {
|
||||
Expr *FirstBad = Inits[1];
|
||||
return ExprError(Diag(FirstBad->getBeginLoc(),
|
||||
diag::err_auto_expr_init_multiple_expressions)
|
||||
<< Ty << FullRange);
|
||||
}
|
||||
if (getLangOpts().CPlusPlus2b) {
|
||||
if (Ty->getAs<AutoType>())
|
||||
Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange;
|
||||
}
|
||||
Expr *Deduce = Inits[0];
|
||||
if (isa<InitListExpr>(Deduce))
|
||||
return ExprError(
|
||||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< ListInitialization << Ty << FullRange);
|
||||
QualType DeducedType;
|
||||
TemplateDeductionInfo Info(Deduce->getExprLoc());
|
||||
TemplateDeductionResult Result =
|
||||
DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
|
||||
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
|
||||
<< Ty << Deduce->getType() << FullRange
|
||||
<< Deduce->getSourceRange());
|
||||
if (DeducedType.isNull()) {
|
||||
assert(Result == TDK_AlreadyDiagnosed);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
Ty = DeducedType;
|
||||
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
|
||||
DeducedType *Deduced = Ty->getContainedDeducedType();
|
||||
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
|
||||
Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity,
|
||||
Kind, Exprs);
|
||||
if (Ty.isNull())
|
||||
return ExprError();
|
||||
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
|
||||
} else if (Deduced) {
|
||||
MultiExprArg Inits = Exprs;
|
||||
if (ListInitialization) {
|
||||
auto *ILE = cast<InitListExpr>(Exprs[0]);
|
||||
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
|
||||
}
|
||||
|
||||
if (Inits.empty())
|
||||
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_init_no_expression)
|
||||
<< Ty << FullRange);
|
||||
if (Inits.size() > 1) {
|
||||
Expr *FirstBad = Inits[1];
|
||||
return ExprError(Diag(FirstBad->getBeginLoc(),
|
||||
diag::err_auto_expr_init_multiple_expressions)
|
||||
<< Ty << FullRange);
|
||||
}
|
||||
if (getLangOpts().CPlusPlus2b) {
|
||||
if (Ty->getAs<AutoType>())
|
||||
Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange;
|
||||
}
|
||||
Expr *Deduce = Inits[0];
|
||||
if (isa<InitListExpr>(Deduce))
|
||||
return ExprError(
|
||||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< ListInitialization << Ty << FullRange);
|
||||
QualType DeducedType;
|
||||
TemplateDeductionInfo Info(Deduce->getExprLoc());
|
||||
TemplateDeductionResult Result =
|
||||
DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
|
||||
return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
|
||||
<< Ty << Deduce->getType() << FullRange
|
||||
<< Deduce->getSourceRange());
|
||||
if (DeducedType.isNull()) {
|
||||
assert(Result == TDK_AlreadyDiagnosed);
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
Ty = DeducedType;
|
||||
Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
|
||||
}
|
||||
|
||||
if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) {
|
||||
@@ -2019,62 +2015,59 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
|
||||
DirectInitRange.getEnd());
|
||||
|
||||
// C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for.
|
||||
if (const DeducedType *Deduced = AllocType->getContainedDeducedType();
|
||||
Deduced && !Deduced->isDeduced()) {
|
||||
if (isa<DeducedTemplateSpecializationType>(Deduced)) {
|
||||
if (ArraySize)
|
||||
return ExprError(
|
||||
Diag(*ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(),
|
||||
diag::err_deduced_class_template_compound_type)
|
||||
<< /*array*/ 2
|
||||
<< (*ArraySize ? (*ArraySize)->getSourceRange() : TypeRange));
|
||||
auto *Deduced = AllocType->getContainedDeducedType();
|
||||
if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
|
||||
if (ArraySize)
|
||||
return ExprError(
|
||||
Diag(*ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(),
|
||||
diag::err_deduced_class_template_compound_type)
|
||||
<< /*array*/ 2
|
||||
<< (*ArraySize ? (*ArraySize)->getSourceRange() : TypeRange));
|
||||
|
||||
InitializedEntity Entity =
|
||||
InitializedEntity::InitializeNew(StartLoc, AllocType);
|
||||
AllocType = DeduceTemplateSpecializationFromInitializer(
|
||||
AllocTypeInfo, Entity, Kind, Exprs);
|
||||
if (AllocType.isNull())
|
||||
return ExprError();
|
||||
} else {
|
||||
assert(isa<AutoType>(Deduced));
|
||||
MultiExprArg Inits = Exprs;
|
||||
bool Braced = (initStyle == CXXNewExpr::ListInit);
|
||||
if (Braced) {
|
||||
auto *ILE = cast<InitListExpr>(Exprs[0]);
|
||||
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
|
||||
}
|
||||
|
||||
if (initStyle == CXXNewExpr::NoInit || Inits.empty())
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
||||
<< AllocType << TypeRange);
|
||||
if (Inits.size() > 1) {
|
||||
Expr *FirstBad = Inits[1];
|
||||
return ExprError(Diag(FirstBad->getBeginLoc(),
|
||||
diag::err_auto_new_ctor_multiple_expressions)
|
||||
<< AllocType << TypeRange);
|
||||
}
|
||||
if (Braced && !getLangOpts().CPlusPlus17)
|
||||
Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init)
|
||||
<< AllocType << TypeRange;
|
||||
Expr *Deduce = Inits[0];
|
||||
if (isa<InitListExpr>(Deduce))
|
||||
return ExprError(
|
||||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< Braced << AllocType << TypeRange);
|
||||
QualType DeducedType;
|
||||
TemplateDeductionInfo Info(Deduce->getExprLoc());
|
||||
TemplateDeductionResult Result = DeduceAutoType(
|
||||
AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
|
||||
<< AllocType << Deduce->getType() << TypeRange
|
||||
<< Deduce->getSourceRange());
|
||||
if (DeducedType.isNull()) {
|
||||
assert(Result == TDK_AlreadyDiagnosed);
|
||||
return ExprError();
|
||||
}
|
||||
AllocType = DeducedType;
|
||||
InitializedEntity Entity
|
||||
= InitializedEntity::InitializeNew(StartLoc, AllocType);
|
||||
AllocType = DeduceTemplateSpecializationFromInitializer(
|
||||
AllocTypeInfo, Entity, Kind, Exprs);
|
||||
if (AllocType.isNull())
|
||||
return ExprError();
|
||||
} else if (Deduced) {
|
||||
MultiExprArg Inits = Exprs;
|
||||
bool Braced = (initStyle == CXXNewExpr::ListInit);
|
||||
if (Braced) {
|
||||
auto *ILE = cast<InitListExpr>(Exprs[0]);
|
||||
Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
|
||||
}
|
||||
|
||||
if (initStyle == CXXNewExpr::NoInit || Inits.empty())
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
|
||||
<< AllocType << TypeRange);
|
||||
if (Inits.size() > 1) {
|
||||
Expr *FirstBad = Inits[1];
|
||||
return ExprError(Diag(FirstBad->getBeginLoc(),
|
||||
diag::err_auto_new_ctor_multiple_expressions)
|
||||
<< AllocType << TypeRange);
|
||||
}
|
||||
if (Braced && !getLangOpts().CPlusPlus17)
|
||||
Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init)
|
||||
<< AllocType << TypeRange;
|
||||
Expr *Deduce = Inits[0];
|
||||
if (isa<InitListExpr>(Deduce))
|
||||
return ExprError(
|
||||
Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
|
||||
<< Braced << AllocType << TypeRange);
|
||||
QualType DeducedType;
|
||||
TemplateDeductionInfo Info(Deduce->getExprLoc());
|
||||
TemplateDeductionResult Result =
|
||||
DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info);
|
||||
if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed)
|
||||
return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
|
||||
<< AllocType << Deduce->getType() << TypeRange
|
||||
<< Deduce->getSourceRange());
|
||||
if (DeducedType.isNull()) {
|
||||
assert(Result == TDK_AlreadyDiagnosed);
|
||||
return ExprError();
|
||||
}
|
||||
AllocType = DeducedType;
|
||||
}
|
||||
|
||||
// Per C++0x [expr.new]p5, the type being constructed may be a
|
||||
@@ -9025,7 +9018,8 @@ Sema::BuildExprRequirement(
|
||||
// be satisfied.
|
||||
TemplateParameterList *TPL =
|
||||
ReturnTypeRequirement.getTypeConstraintTemplateParameterList();
|
||||
QualType MatchedType = Context.getReferenceQualifiedType(E);
|
||||
QualType MatchedType =
|
||||
Context.getReferenceQualifiedType(E).getCanonicalType();
|
||||
llvm::SmallVector<TemplateArgument, 1> Args;
|
||||
Args.push_back(TemplateArgument(MatchedType));
|
||||
|
||||
@@ -9033,7 +9027,7 @@ Sema::BuildExprRequirement(
|
||||
|
||||
TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args);
|
||||
MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray(),
|
||||
/*Final=*/true);
|
||||
/*Final=*/false);
|
||||
MLTAL.addOuterRetainedLevels(TPL->getDepth());
|
||||
Expr *IDC = Param->getTypeConstraint()->getImmediatelyDeclaredConstraint();
|
||||
ExprResult Constraint = SubstExpr(IDC, MLTAL);
|
||||
|
||||
@@ -4875,13 +4875,13 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
|
||||
|
||||
auto *CSD = ImplicitConceptSpecializationDecl::Create(
|
||||
Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
|
||||
SugaredConverted);
|
||||
CanonicalConverted);
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
bool AreArgsDependent =
|
||||
TemplateSpecializationType::anyDependentTemplateArguments(
|
||||
*TemplateArgs, SugaredConverted);
|
||||
MultiLevelTemplateArgumentList MLTAL(NamedConcept, SugaredConverted,
|
||||
/*Final=*/true);
|
||||
*TemplateArgs, CanonicalConverted);
|
||||
MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted,
|
||||
/*Final=*/false);
|
||||
LocalInstantiationScope Scope(*this);
|
||||
|
||||
EnterExpressionEvaluationContext EECtx{
|
||||
@@ -6117,7 +6117,7 @@ bool Sema::CheckTemplateArgumentList(
|
||||
|
||||
if (!PartialTemplateArgs) {
|
||||
TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack,
|
||||
SugaredConverted);
|
||||
CanonicalConverted);
|
||||
// Setup the context/ThisScope for the case where we are needing to
|
||||
// re-instantiate constraints outside of normal instantiation.
|
||||
DeclContext *NewContext = Template->getDeclContext();
|
||||
@@ -6137,7 +6137,7 @@ bool Sema::CheckTemplateArgumentList(
|
||||
CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
|
||||
|
||||
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
|
||||
Template, /*Final=*/true, &StackTemplateArgs,
|
||||
Template, /*Final=*/false, &StackTemplateArgs,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConceptInstantiation=*/true);
|
||||
|
||||
@@ -2869,10 +2869,10 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
|
||||
|
||||
bool NeedsReplacement = DeducedArgsNeedReplacement(Template);
|
||||
TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack,
|
||||
SugaredDeducedArgs};
|
||||
CanonicalDeducedArgs};
|
||||
|
||||
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
|
||||
Template, /*Final=*/true,
|
||||
Template, /*Final=*/false,
|
||||
/*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL,
|
||||
/*RelativeToPrimary=*/true, /*Pattern=*/
|
||||
nullptr, /*ForConstraintInstantiation=*/true);
|
||||
@@ -2882,7 +2882,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
|
||||
// not class-scope explicit specialization, so replace with Deduced Args
|
||||
// instead of adding to inner-most.
|
||||
if (NeedsReplacement)
|
||||
MLTAL.replaceInnermostTemplateArguments(SugaredDeducedArgs);
|
||||
MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs);
|
||||
|
||||
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
|
||||
Info.getLocation(),
|
||||
@@ -4656,8 +4656,8 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
|
||||
/*PartialTemplateArgs=*/false,
|
||||
SugaredConverted, CanonicalConverted))
|
||||
return true;
|
||||
MultiLevelTemplateArgumentList MLTAL(Concept, SugaredConverted,
|
||||
/*Final=*/true);
|
||||
MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted,
|
||||
/*Final=*/false);
|
||||
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
|
||||
MLTAL, TypeLoc.getLocalSourceRange(),
|
||||
Satisfaction))
|
||||
|
||||
@@ -2271,7 +2271,7 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
|
||||
VisitDecl(D);
|
||||
llvm::SmallVector<TemplateArgument, 4> Args;
|
||||
for (unsigned I = 0; I < D->NumTemplateArgs; ++I)
|
||||
Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/false));
|
||||
Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/true));
|
||||
D->setTemplateArguments(Args);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ struct Foo {
|
||||
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept'
|
||||
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13, col:31> 'bool' Concept {{.*}} 'binary_concept'
|
||||
// CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:13:9> col:9
|
||||
// CHECK-NEXT: | |-TemplateArgument type 'R'
|
||||
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
|
||||
// CHECK-NEXT: | | `-TemplateTypeParm {{.*}} 'R'
|
||||
// CHECK-NEXT: | |-TemplateArgument type 'type-parameter-1-0'
|
||||
// CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
|
||||
// CHECK-NEXT: | `-TemplateArgument type 'int'
|
||||
// CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
|
||||
// CHECK-NEXT: |-TemplateArgument {{.*}} type 'R'
|
||||
@@ -36,9 +35,8 @@ struct Foo {
|
||||
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'unary_concept'
|
||||
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13> 'bool'
|
||||
// CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:10:9> col:9
|
||||
// CHECK-NEXT: | `-TemplateArgument type 'R'
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
|
||||
// CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'R'
|
||||
// CHECK-NEXT: | `-TemplateArgument type 'type-parameter-1-0'
|
||||
// CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
|
||||
template <unary_concept R>
|
||||
Foo(R);
|
||||
|
||||
|
||||
@@ -35,14 +35,14 @@ using r2i2 = r2<A>; // expected-error{{constraints not satisfied for class templ
|
||||
using r2i3 = r2<D>;
|
||||
using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}}
|
||||
|
||||
template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
|
||||
template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
|
||||
struct r3 {};
|
||||
|
||||
using r3i1 = r3<int>;
|
||||
using r3i2 = r3<A>;
|
||||
using r3i3 = r3<A &>;
|
||||
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
|
||||
using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
|
||||
using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
|
||||
|
||||
// Non-dependent expressions
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace std_example {
|
||||
template<typename T> constexpr bool is_same_v<T, T> = true;
|
||||
|
||||
template<typename T, typename U> concept same_as = is_same_v<T, U>;
|
||||
// expected-note@-1 {{because 'is_same_v<int, typename T2::inner>' evaluated to false}}
|
||||
// expected-note@-1 {{because 'is_same_v<int, int *>' evaluated to false}}
|
||||
|
||||
static_assert(C1<int>);
|
||||
static_assert(C1<int*>);
|
||||
@@ -173,9 +173,9 @@ namespace std_example {
|
||||
int operator *() { return 0; }
|
||||
};
|
||||
static_assert(C2<T1>);
|
||||
template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'T2' does not satisfy 'C2'}}
|
||||
template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}}
|
||||
using c2c1 = C2_check<int>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}}
|
||||
using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = T2]}}
|
||||
using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}}
|
||||
|
||||
template<typename T>
|
||||
void g(T t) noexcept(sizeof(T) == 1) {}
|
||||
|
||||
@@ -27,7 +27,7 @@ using r4i = X<void>::r4<int>; // expected-error{{constraints not satisfied for c
|
||||
|
||||
// C++ [expr.prim.req.nested] Examples
|
||||
namespace std_example {
|
||||
template<typename U> concept C1 = sizeof(U) == 1; // expected-note{{because 'sizeof(decltype(+t)) == 1' (4 == 1) evaluated to false}}
|
||||
template<typename U> concept C1 = sizeof(U) == 1; // expected-note{{because 'sizeof(int) == 1' (4 == 1) evaluated to false}}
|
||||
template<typename T> concept D =
|
||||
requires (T t) {
|
||||
requires C1<decltype (+t)>; // expected-note{{because 'decltype(+t)' (aka 'int') does not satisfy 'C1'}}
|
||||
|
||||
@@ -39,14 +39,14 @@ using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class
|
||||
|
||||
template<typename T> requires requires { sizeof(T); }
|
||||
// expected-note@-1{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
|
||||
// expected-note@-2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
|
||||
// expected-note@-2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
|
||||
struct r3 {};
|
||||
|
||||
using r3i1 = r3<int>;
|
||||
using r3i2 = r3<A>;
|
||||
using r3i3 = r3<A &>;
|
||||
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
|
||||
using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
|
||||
using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
|
||||
|
||||
template<typename T> requires requires (T t) { 0; "a"; (void)'a'; }
|
||||
struct r4 {};
|
||||
|
||||
@@ -182,14 +182,14 @@ namespace std_example {
|
||||
static_assert(C1<has_inner_and_type> && C2<has_inner_and_type> && C3<has_inner_and_type>);
|
||||
template<C1 T> struct C1_check {};
|
||||
// expected-note@-1 {{because 'int' does not satisfy 'C1'}}
|
||||
// expected-note@-2 {{because 'has_type' does not satisfy 'C1'}}
|
||||
// expected-note@-2 {{because 'std_example::has_type' does not satisfy 'C1'}}
|
||||
template<C2 T> struct C2_check {};
|
||||
// expected-note@-1 {{because 'has_inner' does not satisfy 'C2'}}
|
||||
// expected-note@-1 {{because 'std_example::has_inner' does not satisfy 'C2'}}
|
||||
template<C3 T> struct C3_check {};
|
||||
// expected-note@-1 {{because 'void' does not satisfy 'C3'}}
|
||||
using c1 = C1_check<int>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}}
|
||||
using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = has_type]}}
|
||||
using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = has_inner]}}
|
||||
using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}}
|
||||
using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}}
|
||||
using c4 = C3_check<void>; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}}
|
||||
}
|
||||
|
||||
@@ -199,10 +199,10 @@ template <typename T> concept C = requires { requires requires { T::a; }; };
|
||||
// expected-note@-1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}}
|
||||
|
||||
template <C...> struct A {};
|
||||
// expected-note@-1 {{because 'T1' does not satisfy 'C'}}
|
||||
// expected-note@-1 {{because 'PR48656::T1' does not satisfy 'C'}}
|
||||
|
||||
struct T1 {};
|
||||
template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <T1>]}}
|
||||
template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <PR48656::T1>]}}
|
||||
|
||||
struct T2 { static constexpr bool a = false; };
|
||||
template struct A<T2>;
|
||||
|
||||
@@ -8,7 +8,7 @@ template<typename T> requires Bar<T> && true struct S<T> { };
|
||||
|
||||
template<typename T> concept True2 = sizeof(T) >= 0;
|
||||
template<typename T> concept Foo2 = True2<T*>;
|
||||
// expected-error@-1{{'type name' declared as a pointer to a reference of type 'T &'}}
|
||||
// expected-error@-1{{'type name' declared as a pointer to a reference of type 'type-parameter-0-0 &'}}
|
||||
template<typename T> concept Bar2 = Foo2<T&>;
|
||||
// expected-note@-1{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}}
|
||||
template<typename T> requires Bar2<T> struct S2 { };
|
||||
|
||||
@@ -94,8 +94,8 @@ concept OneOf = (is_same_v<T, Ts> || ...);
|
||||
// expected-note@-5 {{and 'is_same_v<short, char>' evaluated to false}}
|
||||
// expected-note@-6 3{{because 'is_same_v<int, char[1]>' evaluated to false}}
|
||||
// expected-note@-7 3{{and 'is_same_v<int, char[2]>' evaluated to false}}
|
||||
// expected-note@-8 2{{because 'is_same_v<decltype(nullptr), char>' evaluated to false}}
|
||||
// expected-note@-9 2{{and 'is_same_v<decltype(nullptr), int>' evaluated to false}}
|
||||
// expected-note@-8 2{{because 'is_same_v<std::nullptr_t, char>' evaluated to false}}
|
||||
// expected-note@-9 2{{and 'is_same_v<std::nullptr_t, int>' evaluated to false}}
|
||||
|
||||
template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U>
|
||||
// expected-note@-1 2{{because 'OneOf<char, char[1], char[2]>' evaluated to false}}
|
||||
|
||||
@@ -98,25 +98,18 @@ namespace GH50891 {
|
||||
};
|
||||
|
||||
static_assert(Numeric<Deferred>); // #STATIC_ASSERT
|
||||
// expected-error@#OP_TO {{satisfaction of constraint 'Numeric<TO>' depends on itself}}
|
||||
// expected-note@#OP_TO {{while substituting template arguments into constraint expression here}}
|
||||
// FIXME: The following two refer to type-parameter-0-0, it would be nice to
|
||||
// see if we could instead diagnose with the sugared name.
|
||||
// expected-note@#FOO_CALL {{while checking constraint satisfaction for template}}
|
||||
// expected-note@#FOO_CALL {{while substituting deduced template arguments into function template}}
|
||||
// expected-note@#FOO_CALL {{in instantiation of requirement here}}
|
||||
// expected-error@#NUMERIC{{satisfaction of constraint 'requires (T a) { foo(a); }' depends on itself}}
|
||||
// expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
|
||||
// expected-note@#OP_TO {{skipping 2 contexts in backtrace}}
|
||||
// expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
|
||||
// expected-note@#OP_TO {{while substituting template arguments into constraint expression here}}
|
||||
// expected-note@#FOO_CALL {{while checking constraint satisfaction for template}}
|
||||
// expected-note@#FOO_CALL {{in instantiation of function template specialization}}
|
||||
// expected-note@#FOO_CALL {{in instantiation of requirement here}}
|
||||
// expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
|
||||
// expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<Deferred>' requested here}}
|
||||
|
||||
// Fallout of that failure is that deferred does not satisfy numeric,
|
||||
// which is unfortunate, but about what we can accomplish here.
|
||||
// expected-error@#STATIC_ASSERT {{static assertion failed}}
|
||||
// expected-note@#STATIC_ASSERT{{because 'Deferred' does not satisfy 'Numeric'}}
|
||||
// expected-note@#FOO_CALL {{because 'foo(a)' would be invalid}}
|
||||
// expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
|
||||
// expected-note@#STATIC_ASSERT{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
|
||||
|
||||
} // namespace GH50891
|
||||
|
||||
|
||||
@@ -14,13 +14,15 @@ constexpr bool foo() requires (f(T()), true) { return true; }
|
||||
namespace a {
|
||||
struct A {};
|
||||
constexpr void f(A a) {}
|
||||
}
|
||||
|
||||
static_assert(C<A>);
|
||||
static_assert(foo<A>());
|
||||
static_assert(C<a::A>);
|
||||
static_assert(foo<a::A>());
|
||||
|
||||
namespace a {
|
||||
// This makes calls to f ambiguous, but the second check will still succeed
|
||||
// because the constraint satisfaction results are cached.
|
||||
constexpr void f(A a, int = 2) {}
|
||||
static_assert(C<A>);
|
||||
static_assert(foo<A>());
|
||||
} // namespace a
|
||||
}
|
||||
static_assert(C<a::A>);
|
||||
static_assert(foo<a::A>());
|
||||
|
||||
@@ -76,8 +76,8 @@ namespace type_requirement {
|
||||
// expected-note@-2 {{because 'false_v<requires { typename contains_template<short>::temp<contains_template<short> >; }>' evaluated to false}}
|
||||
struct r2 {};
|
||||
|
||||
using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<int>]}}
|
||||
using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<short>]}}
|
||||
using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<int>]}}
|
||||
using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<short>]}}
|
||||
|
||||
// substitution error occurs, then requires expr is instantiated again
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace type_requirement {
|
||||
// expected-note@-1 {{because 'false_v<requires { <<error-type>>; } && requires { <<error-type>>; }>' evaluated to false}}
|
||||
struct r7 {};
|
||||
|
||||
using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, A>]}}
|
||||
using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, type_requirement::A>]}}
|
||||
}
|
||||
|
||||
namespace expr_requirement {
|
||||
@@ -227,13 +227,3 @@ struct r6 {};
|
||||
|
||||
using r6i = r6<int>;
|
||||
// expected-error@-1 {{constraints not satisfied for class template 'r6' [with T = int]}}
|
||||
|
||||
namespace sugared_instantiation {
|
||||
template <class C1> concept C = requires { C1{}; };
|
||||
template <class D1> concept D = requires { new D1; };
|
||||
|
||||
// Test that 'deduced auto' doesn't get confused with 'undeduced auto'.
|
||||
auto f() { return 0; }
|
||||
static_assert(requires { { f() } -> C; });
|
||||
static_assert(requires { { f() } -> D; });
|
||||
} // namespace sugared_instantiation
|
||||
|
||||
@@ -53,7 +53,7 @@ static_assert(!DotFollowingPointer::f(Bad{}), "");
|
||||
#if __cplusplus >= 202002L
|
||||
template <class T>
|
||||
concept C = requires(T t) { t.begin(); };
|
||||
// cxx20-note@-1 {{because 't.begin()' would be invalid: member reference type 'Bad' (aka 'Holder<Incomplete> *') is a pointer}}
|
||||
// cxx20-note@-1 {{because 't.begin()' would be invalid: member reference type 'Holder<Incomplete> *' is a pointer}}
|
||||
|
||||
static_assert(C<Good>);
|
||||
static_assert(!C<Bad>);
|
||||
|
||||
Reference in New Issue
Block a user