mirror of
https://github.com/intel/llvm.git
synced 2026-01-23 16:06:39 +08:00
Revert "[Clang][Sema] Fix comparison of constraint expressions"
This temporarily reverts commit
60bee9ff54.
The diff will be recommitted once the newly discovered
regressions are fixed.
This commit is contained in:
@@ -260,9 +260,6 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
|
||||
return SubstitutedAtomicExpr;
|
||||
}
|
||||
|
||||
if (SubstitutedAtomicExpr.get()->isValueDependent())
|
||||
return SubstitutedAtomicExpr;
|
||||
|
||||
EnterExpressionEvaluationContext ConstantEvaluated(
|
||||
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
||||
SmallVector<PartialDiagnosticAt, 2> EvaluationDiags;
|
||||
@@ -755,43 +752,27 @@ namespace {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static const Expr *SubstituteConstraintExpression(Sema &S, const NamedDecl *ND,
|
||||
const Expr *ConstrExpr) {
|
||||
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
|
||||
ND, /*Final=*/false, /*Innermost=*/nullptr,
|
||||
/*RelativeToPrimary=*/true,
|
||||
/*Pattern=*/nullptr,
|
||||
/*ForConstraintInstantiation=*/true, /*SkipForSpecialization*/ false);
|
||||
if (MLTAL.getNumSubstitutedLevels() == 0)
|
||||
return ConstrExpr;
|
||||
Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/false);
|
||||
std::optional<Sema::CXXThisScopeRAII> ThisScope;
|
||||
if (auto *RD = dyn_cast<CXXRecordDecl>(ND->getDeclContext()))
|
||||
ThisScope.emplace(S, const_cast<CXXRecordDecl *>(RD), Qualifiers());
|
||||
ExprResult SubstConstr =
|
||||
S.SubstConstraintExpr(const_cast<clang::Expr *>(ConstrExpr), MLTAL);
|
||||
if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable())
|
||||
return nullptr;
|
||||
return SubstConstr.get();
|
||||
}
|
||||
|
||||
bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old,
|
||||
const Expr *OldConstr,
|
||||
const NamedDecl *New,
|
||||
const Expr *NewConstr) {
|
||||
if (OldConstr == NewConstr)
|
||||
return true;
|
||||
if (Old && New && Old != New) {
|
||||
if (const Expr *SubstConstr =
|
||||
SubstituteConstraintExpression(*this, Old, OldConstr))
|
||||
OldConstr = SubstConstr;
|
||||
else
|
||||
return false;
|
||||
if (const Expr *SubstConstr =
|
||||
SubstituteConstraintExpression(*this, New, NewConstr))
|
||||
NewConstr = SubstConstr;
|
||||
else
|
||||
return false;
|
||||
unsigned Depth1 = CalculateTemplateDepthForConstraints(
|
||||
*this, Old);
|
||||
unsigned Depth2 = CalculateTemplateDepthForConstraints(
|
||||
*this, New);
|
||||
|
||||
// Adjust the 'shallowest' verison of this to increase the depth to match
|
||||
// the 'other'.
|
||||
if (Depth2 > Depth1) {
|
||||
OldConstr = AdjustConstraintDepth(*this, Depth2 - Depth1)
|
||||
.TransformExpr(const_cast<Expr *>(OldConstr))
|
||||
.get();
|
||||
} else if (Depth1 > Depth2) {
|
||||
NewConstr = AdjustConstraintDepth(*this, Depth1 - Depth2)
|
||||
.TransformExpr(const_cast<Expr *>(NewConstr))
|
||||
.get();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::FoldingSetNodeID ID1, ID2;
|
||||
|
||||
@@ -1294,7 +1294,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
|
||||
// We check the return type and template parameter lists for function
|
||||
// templates first; the remaining checks follow.
|
||||
bool SameTemplateParameterList = TemplateParameterListsAreEqual(
|
||||
NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate,
|
||||
NewTemplate->getTemplateParameters(),
|
||||
OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch);
|
||||
bool SameReturnType = Context.hasSameType(Old->getDeclaredReturnType(),
|
||||
New->getDeclaredReturnType());
|
||||
|
||||
@@ -208,10 +208,6 @@ Response HandleFunction(const FunctionDecl *Function,
|
||||
return Response::UseNextDecl(Function);
|
||||
}
|
||||
|
||||
Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD) {
|
||||
return Response::ChangeDecl(FTD->getLexicalDeclContext());
|
||||
}
|
||||
|
||||
Response HandleRecordDecl(const CXXRecordDecl *Rec,
|
||||
MultiLevelTemplateArgumentList &Result,
|
||||
ASTContext &Context,
|
||||
@@ -322,8 +318,6 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
|
||||
} else if (const auto *CSD =
|
||||
dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) {
|
||||
R = HandleImplicitConceptSpecializationDecl(CSD, Result);
|
||||
} else if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(CurDecl)) {
|
||||
R = HandleFunctionTemplateDecl(FTD);
|
||||
} else if (!isa<DeclContext>(CurDecl)) {
|
||||
R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl);
|
||||
if (CurDecl->getDeclContext()->isTranslationUnit()) {
|
||||
|
||||
@@ -1653,12 +1653,33 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||
<< QualifierLoc.getSourceRange();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (PrevClassTemplate) {
|
||||
const ClassTemplateDecl *MostRecentPrevCT =
|
||||
PrevClassTemplate->getMostRecentDecl();
|
||||
TemplateParameterList *PrevParams =
|
||||
MostRecentPrevCT->getTemplateParameters();
|
||||
|
||||
// Make sure the parameter lists match.
|
||||
if (!SemaRef.TemplateParameterListsAreEqual(
|
||||
D->getTemplatedDecl(), InstParams,
|
||||
MostRecentPrevCT->getTemplatedDecl(), PrevParams, true,
|
||||
Sema::TPL_TemplateMatch))
|
||||
return nullptr;
|
||||
|
||||
// Do some additional validation, then merge default arguments
|
||||
// from the existing declarations.
|
||||
if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
|
||||
Sema::TPC_ClassTemplate))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CXXRecordDecl *RecordInst = CXXRecordDecl::Create(
|
||||
SemaRef.Context, Pattern->getTagKind(), DC, Pattern->getBeginLoc(),
|
||||
Pattern->getLocation(), Pattern->getIdentifier(), PrevDecl,
|
||||
/*DelayTypeCreation=*/true);
|
||||
|
||||
if (QualifierLoc)
|
||||
RecordInst->setQualifierInfo(QualifierLoc);
|
||||
|
||||
@@ -1668,37 +1689,16 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||
ClassTemplateDecl *Inst
|
||||
= ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(),
|
||||
D->getIdentifier(), InstParams, RecordInst);
|
||||
assert(!(isFriend && Owner->isDependentContext()));
|
||||
Inst->setPreviousDecl(PrevClassTemplate);
|
||||
|
||||
RecordInst->setDescribedClassTemplate(Inst);
|
||||
|
||||
if (isFriend) {
|
||||
assert(!Owner->isDependentContext());
|
||||
Inst->setLexicalDeclContext(Owner);
|
||||
RecordInst->setLexicalDeclContext(Owner);
|
||||
|
||||
if (PrevClassTemplate) {
|
||||
RecordInst->setTypeForDecl(
|
||||
PrevClassTemplate->getTemplatedDecl()->getTypeForDecl());
|
||||
const ClassTemplateDecl *MostRecentPrevCT =
|
||||
PrevClassTemplate->getMostRecentDecl();
|
||||
TemplateParameterList *PrevParams =
|
||||
MostRecentPrevCT->getTemplateParameters();
|
||||
|
||||
// Make sure the parameter lists match.
|
||||
if (!SemaRef.TemplateParameterListsAreEqual(
|
||||
RecordInst, InstParams, MostRecentPrevCT->getTemplatedDecl(),
|
||||
PrevParams, true, Sema::TPL_TemplateMatch))
|
||||
return nullptr;
|
||||
|
||||
// Do some additional validation, then merge default arguments
|
||||
// from the existing declarations.
|
||||
if (SemaRef.CheckTemplateParameterList(InstParams, PrevParams,
|
||||
Sema::TPC_ClassTemplate))
|
||||
return nullptr;
|
||||
|
||||
if (PrevClassTemplate)
|
||||
Inst->setAccess(PrevClassTemplate->getAccess());
|
||||
} else {
|
||||
else
|
||||
Inst->setAccess(D->getAccess());
|
||||
}
|
||||
|
||||
Inst->setObjectOfFriendDecl();
|
||||
// TODO: do we want to track the instantiation progeny of this
|
||||
@@ -1709,15 +1709,15 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||
Inst->setInstantiatedFromMemberTemplate(D);
|
||||
}
|
||||
|
||||
Inst->setPreviousDecl(PrevClassTemplate);
|
||||
|
||||
// Trigger creation of the type for the instantiation.
|
||||
SemaRef.Context.getInjectedClassNameType(
|
||||
RecordInst, Inst->getInjectedClassNameSpecialization());
|
||||
SemaRef.Context.getInjectedClassNameType(RecordInst,
|
||||
Inst->getInjectedClassNameSpecialization());
|
||||
|
||||
// Finish handling of friends.
|
||||
if (isFriend) {
|
||||
DC->makeDeclVisibleInContext(Inst);
|
||||
Inst->setLexicalDeclContext(Owner);
|
||||
RecordInst->setLexicalDeclContext(Owner);
|
||||
return Inst;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,153 +127,3 @@ static_assert(S<XY>::specialization("str") == SPECIALIZATION_CONCEPT);
|
||||
static_assert(S<int>::specialization("str") == SPECIALIZATION_REQUIRES);
|
||||
|
||||
} // namespace multiple_template_parameter_lists
|
||||
|
||||
static constexpr int CONSTRAINED_METHOD_1 = 1;
|
||||
static constexpr int CONSTRAINED_METHOD_2 = 2;
|
||||
|
||||
namespace constrained_members {
|
||||
|
||||
template <int>
|
||||
struct S {
|
||||
template <Concept C>
|
||||
static constexpr int constrained_method();
|
||||
};
|
||||
|
||||
template <>
|
||||
template <Concept C>
|
||||
constexpr int S<1>::constrained_method() { return CONSTRAINED_METHOD_1; }
|
||||
|
||||
template <>
|
||||
template <Concept C>
|
||||
constexpr int S<2>::constrained_method() { return CONSTRAINED_METHOD_2; }
|
||||
|
||||
static_assert(S<1>::constrained_method<XY>() == CONSTRAINED_METHOD_1);
|
||||
static_assert(S<2>::constrained_method<XY>() == CONSTRAINED_METHOD_2);
|
||||
|
||||
|
||||
template <class T1, class T2>
|
||||
concept ConceptT1T2 = true;
|
||||
|
||||
template<typename T3>
|
||||
struct S12 {
|
||||
template<ConceptT1T2<T3> T4>
|
||||
static constexpr int constrained_method();
|
||||
};
|
||||
|
||||
template<>
|
||||
template<ConceptT1T2<int> T5>
|
||||
constexpr int S12<int>::constrained_method() { return CONSTRAINED_METHOD_1; }
|
||||
|
||||
template<>
|
||||
template<ConceptT1T2<double> T5>
|
||||
constexpr int S12<double>::constrained_method() { return CONSTRAINED_METHOD_2; }
|
||||
|
||||
static_assert(S12<int>::constrained_method<XY>() == CONSTRAINED_METHOD_1);
|
||||
static_assert(S12<double>::constrained_method<XY>() == CONSTRAINED_METHOD_2);
|
||||
|
||||
} // namespace constrained members
|
||||
|
||||
namespace constrained_members_of_nested_types {
|
||||
|
||||
template <int>
|
||||
struct S {
|
||||
struct Inner0 {
|
||||
struct Inner1 {
|
||||
template <Concept C>
|
||||
static constexpr int constrained_method();
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
template <Concept C>
|
||||
constexpr int S<1>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; }
|
||||
|
||||
template <>
|
||||
template <Concept C>
|
||||
constexpr int S<2>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; }
|
||||
|
||||
static_assert(S<1>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1);
|
||||
static_assert(S<2>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2);
|
||||
|
||||
|
||||
template <class T1, class T2>
|
||||
concept ConceptT1T2 = true;
|
||||
|
||||
template<typename T3>
|
||||
struct S12 {
|
||||
struct Inner0 {
|
||||
struct Inner1 {
|
||||
template<ConceptT1T2<T3> T4>
|
||||
static constexpr int constrained_method();
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
template<ConceptT1T2<int> T5>
|
||||
constexpr int S12<int>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_1; }
|
||||
|
||||
template<>
|
||||
template<ConceptT1T2<double> T5>
|
||||
constexpr int S12<double>::Inner0::Inner1::constrained_method() { return CONSTRAINED_METHOD_2; }
|
||||
|
||||
static_assert(S12<int>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_1);
|
||||
static_assert(S12<double>::Inner0::Inner1::constrained_method<XY>() == CONSTRAINED_METHOD_2);
|
||||
|
||||
} // namespace constrained_members_of_nested_types
|
||||
|
||||
namespace constrained_member_sfinae {
|
||||
|
||||
template<int N> struct S {
|
||||
template<class T>
|
||||
static constexpr int constrained_method() requires (sizeof(int[N * 1073741824 + 4]) == 16) {
|
||||
return CONSTRAINED_METHOD_1;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static constexpr int constrained_method() requires (sizeof(int[N]) == 16);
|
||||
};
|
||||
|
||||
template<>
|
||||
template<typename T>
|
||||
constexpr int S<4>::constrained_method() requires (sizeof(int[4]) == 16) {
|
||||
return CONSTRAINED_METHOD_2;
|
||||
}
|
||||
|
||||
// Verify that there is no amiguity in this case.
|
||||
static_assert(S<4>::constrained_method<double>() == CONSTRAINED_METHOD_2);
|
||||
|
||||
} // namespace constrained_member_sfinae
|
||||
|
||||
namespace requires_expression_references_members {
|
||||
|
||||
void accept1(int x);
|
||||
void accept2(XY xy);
|
||||
|
||||
template <class T> struct S {
|
||||
T Field = T();
|
||||
|
||||
constexpr int constrained_method()
|
||||
requires requires { accept1(Field); };
|
||||
|
||||
constexpr int constrained_method()
|
||||
requires requires { accept2(Field); };
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr int S<T>::constrained_method()
|
||||
requires requires { accept1(Field); } {
|
||||
return CONSTRAINED_METHOD_1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr int S<T>::constrained_method()
|
||||
requires requires { accept2(Field); } {
|
||||
return CONSTRAINED_METHOD_2;
|
||||
}
|
||||
|
||||
static_assert(S<int>().constrained_method() == CONSTRAINED_METHOD_1);
|
||||
static_assert(S<XY>().constrained_method() == CONSTRAINED_METHOD_2);
|
||||
|
||||
} // namespace requires_expression_references_members
|
||||
|
||||
@@ -816,12 +816,3 @@ static_assert(Parent<int>::TakesBinary<int, 0>::i == 0);
|
||||
static_assert(Parent<int>::TakesBinary<int, 0ULL>::i == 0);
|
||||
}
|
||||
|
||||
namespace TemplateInsideNonTemplateClass {
|
||||
template<typename T, typename U> concept C = true;
|
||||
|
||||
template<typename T> auto L = []<C<T> U>() {};
|
||||
|
||||
struct Q {
|
||||
template<C<int> U> friend constexpr auto decltype(L<int>)::operator()() const;
|
||||
};
|
||||
} // namespace TemplateInsideNonTemplateClass
|
||||
|
||||
Reference in New Issue
Block a user