mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 19:06:44 +00:00
Revert "[Clang] Implement CWG2369 "Ordering between constraints and substitution"" (#122130)
Unfortunately that breaks some code on Windows when lambdas come into play, as reported in https://github.com/llvm/llvm-project/pull/102857#issuecomment-2577861178 This reverts commit 96eced624e0f120155256033fdcb8342e7e58d6e.
This commit is contained in:
parent
570f03096a
commit
3972ed5708
@ -13062,7 +13062,6 @@ public:
|
||||
///
|
||||
/// \param SkipForSpecialization when specified, any template specializations
|
||||
/// in a traversal would be ignored.
|
||||
///
|
||||
/// \param ForDefaultArgumentSubstitution indicates we should continue looking
|
||||
/// when encountering a specialized member function template, rather than
|
||||
/// returning immediately.
|
||||
@ -13074,17 +13073,6 @@ public:
|
||||
bool SkipForSpecialization = false,
|
||||
bool ForDefaultArgumentSubstitution = false);
|
||||
|
||||
/// Apart from storing the result to \p Result, this behaves the same as
|
||||
/// another overload.
|
||||
void getTemplateInstantiationArgs(
|
||||
MultiLevelTemplateArgumentList &Result, const NamedDecl *D,
|
||||
const DeclContext *DC = nullptr, bool Final = false,
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
|
||||
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
|
||||
bool ForConstraintInstantiation = false,
|
||||
bool SkipForSpecialization = false,
|
||||
bool ForDefaultArgumentSubstitution = false);
|
||||
|
||||
/// RAII object to handle the state changes required to synthesize
|
||||
/// a function body.
|
||||
class SynthesizedFunctionScope {
|
||||
@ -13354,7 +13342,7 @@ public:
|
||||
ExprResult
|
||||
SubstConstraintExpr(Expr *E,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
// Unlike the above, this does not evaluate constraints.
|
||||
// Unlike the above, this does not evaluates constraints.
|
||||
ExprResult SubstConstraintExprWithoutSatisfaction(
|
||||
Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
|
||||
@ -14475,10 +14463,10 @@ public:
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
SourceRange TemplateIDRange);
|
||||
|
||||
bool CheckFunctionTemplateConstraints(SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Decl,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ConstraintSatisfaction &Satisfaction);
|
||||
bool CheckInstantiatedFunctionTemplateConstraints(
|
||||
SourceLocation PointOfInstantiation, FunctionDecl *Decl,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ConstraintSatisfaction &Satisfaction);
|
||||
|
||||
/// \brief Emit diagnostics explaining why a constraint expression was deemed
|
||||
/// unsatisfied.
|
||||
|
@ -522,12 +522,6 @@ enum class TemplateSubstitutionKind : char {
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> *
|
||||
findInstantiationOf(const Decl *D);
|
||||
|
||||
/// Similar to \p findInstantiationOf(), but it wouldn't assert if the
|
||||
/// instantiation was not found within the current instantiation scope. This
|
||||
/// is helpful for on-demand declaration instantiation.
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> *
|
||||
findInstantiationUnsafe(const Decl *D);
|
||||
|
||||
void InstantiatedLocal(const Decl *D, Decl *Inst);
|
||||
void InstantiatedLocalPackArg(const Decl *D, VarDecl *Inst);
|
||||
void MakeInstantiatedLocalArgPack(const Decl *D);
|
||||
|
@ -846,7 +846,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
|
||||
bool ForOverloadResolution) {
|
||||
// Don't check constraints if the function is dependent. Also don't check if
|
||||
// this is a function template specialization, as the call to
|
||||
// CheckFunctionTemplateConstraints after this will check it
|
||||
// CheckinstantiatedFunctionTemplateConstraints after this will check it
|
||||
// better.
|
||||
if (FD->isDependentContext() ||
|
||||
FD->getTemplatedKind() ==
|
||||
@ -1111,55 +1111,12 @@ bool Sema::EnsureTemplateArgumentListConstraints(
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CheckFunctionConstraintsWithoutInstantiation(
|
||||
Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
FunctionTemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ConstraintSatisfaction &Satisfaction) {
|
||||
SmallVector<const Expr *, 3> TemplateAC;
|
||||
Template->getAssociatedConstraints(TemplateAC);
|
||||
if (TemplateAC.empty()) {
|
||||
Satisfaction.IsSatisfied = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
LocalInstantiationScope Scope(SemaRef);
|
||||
|
||||
FunctionDecl *FD = Template->getTemplatedDecl();
|
||||
// Collect the list of template arguments relative to the 'primary'
|
||||
// template. We need the entire list, since the constraint is completely
|
||||
// uninstantiated at this point.
|
||||
|
||||
// FIXME: Add TemplateArgs through the 'Innermost' parameter once
|
||||
// the refactoring of getTemplateInstantiationArgs() relands.
|
||||
MultiLevelTemplateArgumentList MLTAL;
|
||||
MLTAL.addOuterTemplateArguments(Template, std::nullopt, /*Final=*/false);
|
||||
SemaRef.getTemplateInstantiationArgs(
|
||||
MLTAL, /*D=*/FD, FD,
|
||||
/*Final=*/false, /*Innermost=*/std::nullopt, /*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr, /*ForConstraintInstantiation=*/true);
|
||||
MLTAL.replaceInnermostTemplateArguments(Template, TemplateArgs);
|
||||
|
||||
Sema::ContextRAII SavedContext(SemaRef, FD);
|
||||
std::optional<Sema::CXXThisScopeRAII> ThisScope;
|
||||
if (auto *Method = dyn_cast<CXXMethodDecl>(FD))
|
||||
ThisScope.emplace(SemaRef, /*Record=*/Method->getParent(),
|
||||
/*ThisQuals=*/Method->getMethodQualifiers());
|
||||
return SemaRef.CheckConstraintSatisfaction(
|
||||
Template, TemplateAC, MLTAL, PointOfInstantiation, Satisfaction);
|
||||
}
|
||||
|
||||
bool Sema::CheckFunctionTemplateConstraints(
|
||||
bool Sema::CheckInstantiatedFunctionTemplateConstraints(
|
||||
SourceLocation PointOfInstantiation, FunctionDecl *Decl,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ConstraintSatisfaction &Satisfaction) {
|
||||
// In most cases we're not going to have constraints, so check for that first.
|
||||
FunctionTemplateDecl *Template = Decl->getPrimaryTemplate();
|
||||
|
||||
if (!Template)
|
||||
return ::CheckFunctionConstraintsWithoutInstantiation(
|
||||
*this, PointOfInstantiation, Decl->getDescribedFunctionTemplate(),
|
||||
TemplateArgs, Satisfaction);
|
||||
|
||||
// Note - code synthesis context for the constraints check is created
|
||||
// inside CheckConstraintsSatisfaction.
|
||||
SmallVector<const Expr *, 3> TemplateAC;
|
||||
|
@ -3936,6 +3936,18 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
|
||||
Result != TemplateDeductionResult::Success)
|
||||
return Result;
|
||||
|
||||
// C++ [temp.deduct.call]p10: [DR1391]
|
||||
// If deduction succeeds for all parameters that contain
|
||||
// template-parameters that participate in template argument deduction,
|
||||
// and all template arguments are explicitly specified, deduced, or
|
||||
// obtained from default template arguments, remaining parameters are then
|
||||
// compared with the corresponding arguments. For each remaining parameter
|
||||
// P with a type that was non-dependent before substitution of any
|
||||
// explicitly-specified template arguments, if the corresponding argument
|
||||
// A cannot be implicitly converted to P, deduction fails.
|
||||
if (CheckNonDependent())
|
||||
return TemplateDeductionResult::NonDependentConversionFailure;
|
||||
|
||||
// Form the template argument list from the deduced template arguments.
|
||||
TemplateArgumentList *SugaredDeducedArgumentList =
|
||||
TemplateArgumentList::CreateCopy(Context, SugaredBuilder);
|
||||
@ -3965,39 +3977,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
|
||||
FD = const_cast<FunctionDecl *>(FDFriend);
|
||||
Owner = FD->getLexicalDeclContext();
|
||||
}
|
||||
// C++20 [temp.deduct.general]p5: [CWG2369]
|
||||
// If the function template has associated constraints, those constraints
|
||||
// are checked for satisfaction. If the constraints are not satisfied, type
|
||||
// deduction fails.
|
||||
//
|
||||
// FIXME: We haven't implemented CWG2369 for lambdas yet, because we need
|
||||
// to figure out how to instantiate lambda captures to the scope without
|
||||
// first instantiating the lambda.
|
||||
bool IsLambda = isLambdaCallOperator(FD) || isLambdaConversionOperator(FD);
|
||||
if (!IsLambda && !IsIncomplete) {
|
||||
if (CheckFunctionTemplateConstraints(
|
||||
Info.getLocation(),
|
||||
FunctionTemplate->getCanonicalDecl()->getTemplatedDecl(),
|
||||
CanonicalBuilder, Info.AssociatedConstraintsSatisfaction))
|
||||
return TemplateDeductionResult::MiscellaneousDeductionFailure;
|
||||
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
|
||||
Info.reset(Info.takeSugared(),
|
||||
TemplateArgumentList::CreateCopy(Context, CanonicalBuilder));
|
||||
return TemplateDeductionResult::ConstraintsNotSatisfied;
|
||||
}
|
||||
}
|
||||
// C++ [temp.deduct.call]p10: [CWG1391]
|
||||
// If deduction succeeds for all parameters that contain
|
||||
// template-parameters that participate in template argument deduction,
|
||||
// and all template arguments are explicitly specified, deduced, or
|
||||
// obtained from default template arguments, remaining parameters are then
|
||||
// compared with the corresponding arguments. For each remaining parameter
|
||||
// P with a type that was non-dependent before substitution of any
|
||||
// explicitly-specified template arguments, if the corresponding argument
|
||||
// A cannot be implicitly converted to P, deduction fails.
|
||||
if (CheckNonDependent())
|
||||
return TemplateDeductionResult::NonDependentConversionFailure;
|
||||
|
||||
MultiLevelTemplateArgumentList SubstArgs(
|
||||
FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
|
||||
/*Final=*/false);
|
||||
@ -4032,8 +4011,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
|
||||
// ([temp.constr.decl]), those constraints are checked for satisfaction
|
||||
// ([temp.constr.constr]). If the constraints are not satisfied, type
|
||||
// deduction fails.
|
||||
if (IsLambda && !IsIncomplete) {
|
||||
if (CheckFunctionTemplateConstraints(
|
||||
if (!IsIncomplete) {
|
||||
if (CheckInstantiatedFunctionTemplateConstraints(
|
||||
Info.getLocation(), Specialization, CanonicalBuilder,
|
||||
Info.AssociatedConstraintsSatisfaction))
|
||||
return TemplateDeductionResult::MiscellaneousDeductionFailure;
|
||||
|
@ -902,12 +902,10 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
|
||||
Context.getTrivialTypeSourceInfo(
|
||||
Context.getDeducedTemplateSpecializationType(
|
||||
TemplateName(AliasTemplate), /*DeducedType=*/QualType(),
|
||||
/*IsDependent=*/true),
|
||||
AliasTemplate->getLocation()), // template specialization type whose
|
||||
// arguments will be deduced.
|
||||
/*IsDependent=*/true)), // template specialization type whose
|
||||
// arguments will be deduced.
|
||||
Context.getTrivialTypeSourceInfo(
|
||||
ReturnType, AliasTemplate->getLocation()), // type from which template
|
||||
// arguments are deduced.
|
||||
ReturnType), // type from which template arguments are deduced.
|
||||
};
|
||||
return TypeTraitExpr::Create(
|
||||
Context, Context.getLogicalOperationType(), AliasTemplate->getLocation(),
|
||||
|
@ -475,21 +475,6 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
|
||||
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
|
||||
// Accumulate the set of template argument lists in this structure.
|
||||
MultiLevelTemplateArgumentList Result;
|
||||
getTemplateInstantiationArgs(
|
||||
Result, ND, DC, Final, Innermost, RelativeToPrimary, Pattern,
|
||||
ForConstraintInstantiation, SkipForSpecialization,
|
||||
ForDefaultArgumentSubstitution);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void Sema::getTemplateInstantiationArgs(
|
||||
MultiLevelTemplateArgumentList &Result, const NamedDecl *ND,
|
||||
const DeclContext *DC, bool Final,
|
||||
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
|
||||
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
|
||||
bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
|
||||
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
|
||||
// Accumulate the set of template argument lists in this structure.
|
||||
|
||||
using namespace TemplateInstArgsHelpers;
|
||||
const Decl *CurDecl = ND;
|
||||
@ -550,12 +535,14 @@ void Sema::getTemplateInstantiationArgs(
|
||||
}
|
||||
|
||||
if (R.IsDone)
|
||||
return;
|
||||
return Result;
|
||||
if (R.ClearRelativeToPrimary)
|
||||
RelativeToPrimary = false;
|
||||
assert(R.NextDecl);
|
||||
CurDecl = R.NextDecl;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool Sema::CodeSynthesisContext::isInstantiationRecord() const {
|
||||
@ -1362,19 +1349,6 @@ namespace {
|
||||
// Whether an incomplete substituion should be treated as an error.
|
||||
bool BailOutOnIncomplete;
|
||||
|
||||
private:
|
||||
bool isSubstitutingConstraints() const {
|
||||
return llvm::any_of(SemaRef.CodeSynthesisContexts, [](auto &Context) {
|
||||
return Context.Kind ==
|
||||
Sema::CodeSynthesisContext::ConstraintSubstitution;
|
||||
});
|
||||
}
|
||||
|
||||
// CWG2770: Function parameters should be instantiated when they are
|
||||
// needed by a satisfaction check of an atomic constraint or
|
||||
// (recursively) by another function parameter.
|
||||
bool maybeInstantiateFunctionParameterToScope(ParmVarDecl *OldParm);
|
||||
|
||||
public:
|
||||
typedef TreeTransform<TemplateInstantiator> inherited;
|
||||
|
||||
@ -1431,19 +1405,12 @@ namespace {
|
||||
ArrayRef<UnexpandedParameterPack> Unexpanded,
|
||||
bool &ShouldExpand, bool &RetainExpansion,
|
||||
std::optional<unsigned> &NumExpansions) {
|
||||
if (SemaRef.CurrentInstantiationScope && isSubstitutingConstraints()) {
|
||||
for (UnexpandedParameterPack ParmPack : Unexpanded) {
|
||||
NamedDecl *VD = ParmPack.first.dyn_cast<NamedDecl *>();
|
||||
if (!isa_and_present<ParmVarDecl>(VD))
|
||||
continue;
|
||||
if (maybeInstantiateFunctionParameterToScope(cast<ParmVarDecl>(VD)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return getSema().CheckParameterPacksForExpansion(
|
||||
EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, ShouldExpand,
|
||||
RetainExpansion, NumExpansions);
|
||||
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
|
||||
PatternRange, Unexpanded,
|
||||
TemplateArgs,
|
||||
ShouldExpand,
|
||||
RetainExpansion,
|
||||
NumExpansions);
|
||||
}
|
||||
|
||||
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
|
||||
@ -1944,62 +1911,9 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
|
||||
// template parameter.
|
||||
}
|
||||
|
||||
if (SemaRef.CurrentInstantiationScope) {
|
||||
if (isSubstitutingConstraints() && isa<ParmVarDecl>(D) &&
|
||||
maybeInstantiateFunctionParameterToScope(cast<ParmVarDecl>(D)))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return SemaRef.FindInstantiatedDecl(Loc, cast<NamedDecl>(D), TemplateArgs);
|
||||
}
|
||||
|
||||
bool TemplateInstantiator::maybeInstantiateFunctionParameterToScope(
|
||||
ParmVarDecl *OldParm) {
|
||||
if (SemaRef.CurrentInstantiationScope->findInstantiationUnsafe(OldParm))
|
||||
return false;
|
||||
// We're instantiating a function parameter whose associated function template
|
||||
// has not been instantiated at this point for constraint evaluation, so make
|
||||
// sure the instantiated parameters are owned by a function declaration such
|
||||
// that they can be correctly 'captured' in tryCaptureVariable().
|
||||
Sema::ContextRAII Context(SemaRef, OldParm->getDeclContext());
|
||||
|
||||
if (!OldParm->isParameterPack())
|
||||
return !TransformFunctionTypeParam(OldParm, /*indexAdjustment=*/0,
|
||||
/*NumExpansions=*/std::nullopt,
|
||||
/*ExpectParameterPack=*/false);
|
||||
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
|
||||
// Find the parameter packs that could be expanded.
|
||||
TypeLoc TL = OldParm->getTypeSourceInfo()->getTypeLoc();
|
||||
PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>();
|
||||
TypeLoc Pattern = ExpansionTL.getPatternLoc();
|
||||
SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded);
|
||||
assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
|
||||
|
||||
bool ShouldExpand = false;
|
||||
bool RetainExpansion = false;
|
||||
std::optional<unsigned> OrigNumExpansions =
|
||||
ExpansionTL.getTypePtr()->getNumExpansions();
|
||||
std::optional<unsigned> NumExpansions = OrigNumExpansions;
|
||||
if (TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
|
||||
Pattern.getSourceRange(), Unexpanded,
|
||||
ShouldExpand, RetainExpansion, NumExpansions))
|
||||
return true;
|
||||
|
||||
assert(ShouldExpand && !RetainExpansion &&
|
||||
"Shouldn't preserve pack expansion when evaluating constraints");
|
||||
ExpandingFunctionParameterPack(OldParm);
|
||||
for (unsigned I = 0; I != *NumExpansions; ++I) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
|
||||
if (!TransformFunctionTypeParam(OldParm, /*indexAdjustment=*/0,
|
||||
/*NumExpansions=*/OrigNumExpansions,
|
||||
/*ExpectParameterPack=*/false))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Decl *TemplateInstantiator::TransformDefinition(SourceLocation Loc, Decl *D) {
|
||||
Decl *Inst = getSema().SubstDecl(D, getSema().CurContext, TemplateArgs);
|
||||
if (!Inst)
|
||||
@ -4677,8 +4591,9 @@ static const Decl *getCanonicalParmVarDecl(const Decl *D) {
|
||||
return D;
|
||||
}
|
||||
|
||||
|
||||
llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
|
||||
LocalInstantiationScope::findInstantiationUnsafe(const Decl *D) {
|
||||
LocalInstantiationScope::findInstantiationOf(const Decl *D) {
|
||||
D = getCanonicalParmVarDecl(D);
|
||||
for (LocalInstantiationScope *Current = this; Current;
|
||||
Current = Current->Outer) {
|
||||
@ -4703,14 +4618,6 @@ LocalInstantiationScope::findInstantiationUnsafe(const Decl *D) {
|
||||
break;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
|
||||
LocalInstantiationScope::findInstantiationOf(const Decl *D) {
|
||||
auto *Result = findInstantiationUnsafe(D);
|
||||
if (Result)
|
||||
return Result;
|
||||
// If we're performing a partial substitution during template argument
|
||||
// deduction, we may not have values for template parameters yet.
|
||||
if (isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
|
||||
|
@ -713,7 +713,7 @@ public:
|
||||
/// variables vector are acceptable.
|
||||
///
|
||||
/// LastParamTransformed, if non-null, will be set to the index of the last
|
||||
/// parameter on which transformation was started. In the event of an error,
|
||||
/// parameter on which transfromation was started. In the event of an error,
|
||||
/// this will contain the parameter which failed to instantiate.
|
||||
///
|
||||
/// Return true on error.
|
||||
|
@ -365,35 +365,6 @@ struct A {
|
||||
#endif
|
||||
} // namespace cwg2363
|
||||
|
||||
namespace cwg2369 { // cwg2369: partial
|
||||
#if __cplusplus >= 202002L
|
||||
template <class T> struct Z {
|
||||
typedef typename T::x xx;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
concept C = requires { typename T::A; };
|
||||
template <C T> typename Z<T>::xx f(void *, T); // #1
|
||||
template <class T> void f(int, T); // #2
|
||||
|
||||
struct A {
|
||||
} a;
|
||||
|
||||
struct ZZ {
|
||||
template <class T, class = typename Z<T>::xx> operator T *();
|
||||
operator int();
|
||||
};
|
||||
|
||||
void foo() {
|
||||
ZZ zz;
|
||||
f(1, a); // OK, deduction fails for #1 because there is no conversion from int
|
||||
// to void*
|
||||
f(zz, 42); // OK, deduction fails for #1 because C<int> is not satisfied
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace cwg2369
|
||||
|
||||
namespace cwg2370 { // cwg2370: no
|
||||
namespace N {
|
||||
typedef int type;
|
||||
|
@ -319,7 +319,7 @@ void f(T) requires requires { []() { T::invalid; } (); };
|
||||
// since-cxx20-note@-3 {{in instantiation of requirement here}}
|
||||
// since-cxx20-note@-4 {{while substituting template arguments into constraint expression here}}
|
||||
// since-cxx20-note@#cwg2672-f-0 {{while checking constraint satisfaction for template 'f<int>' required here}}
|
||||
// since-cxx20-note@#cwg2672-f-0 {{while substituting deduced template arguments into function template 'f' [with T = int]}}
|
||||
// since-cxx20-note@#cwg2672-f-0 {{in instantiation of function template specialization 'cwg2672::f<int>' requested here}}
|
||||
void f(...);
|
||||
|
||||
template <class T>
|
||||
|
@ -174,26 +174,6 @@ static_assert(!__is_layout_compatible(StructWithAnonUnion, StructWithAnonUnion3)
|
||||
#endif
|
||||
} // namespace cwg2759
|
||||
|
||||
namespace cwg2770 { // cwg2770: 20 open 2023-07-14
|
||||
#if __cplusplus >= 202002L
|
||||
template<typename T>
|
||||
struct B {
|
||||
static_assert(sizeof(T) == 1);
|
||||
using type = int;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
int f(T t, typename B<T>::type u) requires (sizeof(t) == 1);
|
||||
|
||||
template<typename T>
|
||||
int f(T t, long);
|
||||
|
||||
int i = f(1, 2);
|
||||
int j = f('a', 2);
|
||||
|
||||
#endif
|
||||
} // namespace cwg2770
|
||||
|
||||
namespace cwg2789 { // cwg2789: 18
|
||||
#if __cplusplus >= 202302L
|
||||
template <typename T = int>
|
||||
|
@ -154,7 +154,7 @@ void func() {
|
||||
|
||||
bar<int>();
|
||||
// expected-note@-1 {{while checking constraint satisfaction for template 'bar<int>' required here}} \
|
||||
// expected-note@-1 {{while substituting deduced template arguments into function template 'bar' [with T = int]}}
|
||||
// expected-note@-1 {{in instantiation of function template specialization}}
|
||||
// expected-note@#bar {{in instantiation of static data member}}
|
||||
// expected-note@#bar {{in instantiation of requirement here}}
|
||||
// expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
|
||||
|
@ -11,7 +11,7 @@ template<typename T> struct S {
|
||||
|
||||
// expected-error@+3{{atomic constraint must be of type 'bool' (found 'S<int>')}}
|
||||
// expected-note@#FINST{{while checking constraint satisfaction}}
|
||||
// expected-note@#FINST{{while substituting deduced template arguments into function template 'f' [with T = int]}}
|
||||
// expected-note@#FINST{{in instantiation of function template specialization}}
|
||||
template<typename T> requires (S<T>{})
|
||||
void f(T);
|
||||
void f(int);
|
||||
@ -19,7 +19,7 @@ void f(int);
|
||||
// Ensure this applies to operator && as well.
|
||||
// expected-error@+3{{atomic constraint must be of type 'bool' (found 'S<int>')}}
|
||||
// expected-note@#F2INST{{while checking constraint satisfaction}}
|
||||
// expected-note@#F2INST{{while substituting deduced template arguments into function template 'f2' [with T = int]}}
|
||||
// expected-note@#F2INST{{in instantiation of function template specialization}}
|
||||
template<typename T> requires (S<T>{} && true)
|
||||
void f2(T);
|
||||
void f2(int);
|
||||
@ -32,7 +32,7 @@ template<typename T> requires requires {
|
||||
// expected-note@-4{{while checking the satisfaction}}
|
||||
// expected-note@-6{{while substituting template arguments}}
|
||||
// expected-note@#F3INST{{while checking constraint satisfaction}}
|
||||
// expected-note@#F3INST{{while substituting deduced template arguments into function template 'f3' [with T = int]}}
|
||||
// expected-note@#F3INST{{in instantiation of function template specialization}}
|
||||
//
|
||||
}
|
||||
void f3(T);
|
||||
|
@ -31,7 +31,7 @@ void function() {
|
||||
// expected-note@#3 {{checking the satisfaction of concept 'convertible_to<bool, bool>'}}
|
||||
// expected-note@#2 {{substituting template arguments into constraint expression here}}
|
||||
// expected-note@#5 {{checking constraint satisfaction for template 'compare<Object *, Object *>'}}
|
||||
// expected-note@#5 {{while substituting deduced template arguments into function template 'compare' [with IteratorL = Object *, IteratorR = Object *]}}
|
||||
// expected-note@#5 {{in instantiation of function template specialization 'compare<Object *, Object *>' requested here}}
|
||||
|
||||
// expected-note@#4 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
|
||||
// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
|
||||
|
@ -196,7 +196,7 @@ struct Foo {
|
||||
|
||||
template <int K>
|
||||
using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
|
||||
// expected-note@-1 {{candidate template ignored: could not match}} expected-note@-1 {{candidate template ignored: constraints not satisfied}}
|
||||
// expected-note@-1 {{candidate template ignored: could not match}}
|
||||
// expected-note@-2 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(Foo<double, K>) -> Foo<double, K>'}}
|
||||
// expected-note@-3 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(const double (&)[K]) -> Foo<double, K>'}}
|
||||
double abc[3];
|
||||
|
@ -129,12 +129,12 @@ constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while che
|
||||
|
||||
static_assert(f5<int>() == 1);
|
||||
static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint satisfaction}}
|
||||
// expected-note@-1 3 {{while substituting deduced template arguments}}
|
||||
// expected-note@-1 3 {{in instantiation of}}
|
||||
// expected-error@-2 {{no matching function for call}}
|
||||
|
||||
static_assert(f5<double>() == 2);
|
||||
static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{while substituting deduced template arguments}}
|
||||
static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{while substituting deduced template arguments}}
|
||||
static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
|
||||
static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
|
||||
|
||||
// Do not validate assumptions whose evaluation would have side-effects.
|
||||
constexpr int foo() {
|
||||
|
@ -233,7 +233,7 @@ void g() {
|
||||
A<Thingy, Thingy> *ap;
|
||||
f(ap, ap); // expected-error{{no matching function for call to 'f'}} \
|
||||
// expected-note {{while checking constraint satisfaction}} \
|
||||
// expected-note {{while substituting deduced template arguments}}
|
||||
// expected-note {{in instantiation of function template specialization}}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ int* func(T) requires requires { []() { T::foo(); }; }; // expected-error{{type
|
||||
double* func(...);
|
||||
|
||||
static_assert(__is_same(decltype(func(0)), double*)); // expected-note {{while checking constraint satisfaction for template 'func<int>' required here}}
|
||||
// expected-note@-1 {{while substituting deduced template arguments into function template 'func' [with T = int]}}
|
||||
// expected-note@-1 {{in instantiation of function template specialization 'lambda_in_constraints::func<int>'}}
|
||||
static_assert(__is_same(decltype(func(WithFoo())), int*));
|
||||
|
||||
template <class T>
|
||||
@ -252,7 +252,7 @@ S s("a"); // #use
|
||||
// expected-note@#S-requires {{substituting template arguments into constraint expression here}}
|
||||
// expected-note@#S-requires {{in instantiation of requirement here}}
|
||||
// expected-note@#use {{checking constraint satisfaction for template 'S<const char *>' required here}}
|
||||
// expected-note@#use {{while substituting deduced template arguments into function template 'S' [with value:auto = const char *]}}
|
||||
// expected-note@#use {{requested here}}
|
||||
// expected-note-re@#S 2{{candidate constructor {{.*}} not viable}}
|
||||
// expected-note@#S-ctor {{constraints not satisfied}}
|
||||
// expected-note-re@#S-requires {{because {{.*}} would be invalid}}
|
||||
|
@ -76,7 +76,7 @@ auto it = begin(rng); // #BEGIN_CALL
|
||||
// expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<DirectRecursiveCheck::my_range>' requested here}}
|
||||
// expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
|
||||
// expected-note@#BEGIN_CALL {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
|
||||
// expected-note@#BEGIN_CALL {{while substituting deduced template arguments into function template}}
|
||||
// expected-note@#BEGIN_CALL {{in instantiation of function template specialization}}
|
||||
|
||||
// Fallout of the failure is failed lookup, which is necessary to stop odd
|
||||
// cascading errors.
|
||||
@ -103,7 +103,7 @@ namespace GH50891 {
|
||||
// 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 {{while substituting deduced template arguments into function 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}}
|
||||
|
||||
|
@ -34,7 +34,7 @@ namespace constant_evaluated {
|
||||
expected-note@-1{{candidate template ignored}}
|
||||
int a = (foo<int>(), 0);
|
||||
// expected-note@-1 {{while checking}} expected-error@-1{{no matching function}} \
|
||||
expected-note@-1 {{while substituting}}
|
||||
expected-note@-1 {{in instantiation}}
|
||||
template<typename T> void bar() requires requires { requires f<int[2]>; } { };
|
||||
// expected-note@-1{{in instantiation}} \
|
||||
expected-note@-1{{while substituting}} \
|
||||
|
@ -234,6 +234,11 @@ F s(0);
|
||||
// CHECK: | `-CXXBoolLiteralExpr {{.*}} 'bool' false
|
||||
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (U) -> F<>'
|
||||
// CHECK: | `-ParmVarDecl {{.*}} 'U'
|
||||
// CHECK: `-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (int) -> F<>'
|
||||
// CHECK: |-TemplateArgument integral ''x''
|
||||
// CHECK: |-TemplateArgument type 'int'
|
||||
// CHECK: | `-BuiltinType {{.*}} 'int'
|
||||
// CHECK: `-ParmVarDecl {{.*}} 'int'
|
||||
// CHECK: FunctionProtoType {{.*}} 'auto (U) -> F<>' dependent trailing_return cdecl
|
||||
// CHECK: |-InjectedClassNameType {{.*}} 'F<>' dependent
|
||||
// CHECK: | `-CXXRecord {{.*}} 'F'
|
||||
|
@ -38,7 +38,7 @@ template<typename A, typename T>
|
||||
concept True = true;
|
||||
|
||||
template<typename T>
|
||||
concept False = false; // #False
|
||||
concept False = false;
|
||||
|
||||
template<class X> struct concepts {
|
||||
template<class Y> struct B {
|
||||
@ -68,7 +68,7 @@ template<typename X> struct nested_init_list {
|
||||
Y y;
|
||||
};
|
||||
|
||||
template<False F> // #INIT_LIST_INNER_INVALID_HEADER
|
||||
template<False F>
|
||||
struct concept_fail { // #INIT_LIST_INNER_INVALID
|
||||
X x;
|
||||
F f;
|
||||
@ -81,9 +81,7 @@ using NIL = nested_init_list<int>::B<int>;
|
||||
|
||||
// expected-error@+1 {{no viable constructor or deduction guide for deduction of template arguments of 'nested_init_list<int>::concept_fail'}}
|
||||
nested_init_list<int>::concept_fail nil_invalid{1, ""};
|
||||
// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: constraints not satisfied [with F = const char *]}}
|
||||
// expected-note@#INIT_LIST_INNER_INVALID_HEADER {{because 'const char *' does not satisfy 'False'}}
|
||||
// expected-note@#False {{because 'false' evaluated to false}}
|
||||
// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: substitution failure [with F = const char *]: constraints not satisfied for class template 'concept_fail' [with F = const char *]}}
|
||||
// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(int, F) -> concept_fail<F>'}}
|
||||
// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 1 argument, but 2 were provided}}
|
||||
// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(concept_fail<F>) -> concept_fail<F>'}}
|
||||
|
@ -14045,7 +14045,7 @@ and <I>POD class</I></td>
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2369.html">2369</a></td>
|
||||
<td>CD6</td>
|
||||
<td>Ordering between constraints and substitution</td>
|
||||
<td class="partial" align="center">Partial</td>
|
||||
<td class="unknown" align="center">Unknown</td>
|
||||
</tr>
|
||||
<tr id="2370">
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2370.html">2370</a></td>
|
||||
@ -16464,11 +16464,7 @@ objects</td>
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2770.html">2770</a></td>
|
||||
<td>open</td>
|
||||
<td>Trailing <I>requires-clause</I> can refer to function parameters before they are substituted into</td>
|
||||
<td align="center">
|
||||
<details>
|
||||
<summary>Not resolved</summary>
|
||||
Clang 20 implements 2023-07-14 resolution
|
||||
</details></td>
|
||||
<td align="center">Not resolved</td>
|
||||
</tr>
|
||||
<tr id="2771">
|
||||
<td><a href="https://cplusplus.github.io/CWG/issues/2771.html">2771</a></td>
|
||||
|
Loading…
x
Reference in New Issue
Block a user