[clang] 14335be - [Clang][NFC] Minor constraint satisfaction checking cleanup (#134059)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 2 04:49:52 PDT 2025
Author: cor3ntin
Date: 2025-04-02T13:49:48+02:00
New Revision: 14335be0780d369f4aa2403ee986bac3d436872f
URL: https://github.com/llvm/llvm-project/commit/14335be0780d369f4aa2403ee986bac3d436872f
DIFF: https://github.com/llvm/llvm-project/commit/14335be0780d369f4aa2403ee986bac3d436872f.diff
LOG: [Clang][NFC] Minor constraint satisfaction checking cleanup (#134059)
We had a weird, incorrect, "ConstraintEvaluator" object that was not
useful for anything, so I removed that.
I also changed the CheckConstraintSatisfaction overload that just took
an Expr* as this did not make much sense at all.
Satisfaction checking is still fairly wrong,
we do not follow the standard that requires we only substitute into the
mapping of the normal form, so we produce errors for incorrect
substitution into concepts id, even though we should not.
Added:
Modified:
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaConcept.cpp
clang/lib/Sema/SemaDeclCXX.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6e504b7211567..a62562bb134f5 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14597,8 +14597,9 @@ class Sema final : public SemaBase {
/// occurred and satisfaction could not be determined.
///
/// \returns true if an error occurred, false otherwise.
- bool CheckConstraintSatisfaction(const Expr *ConstraintExpr,
- ConstraintSatisfaction &Satisfaction);
+ bool
+ CheckConstraintSatisfaction(const ConceptSpecializationExpr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction);
/// Check whether the given function decl's trailing requires clause is
/// satisfied, if any. Returns false and updates Satisfaction with the
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index e6117f97ad1f4..5e1cd62530c5b 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -176,22 +176,167 @@ struct SatisfactionStackRAII {
};
} // namespace
-template <typename ConstraintEvaluator>
-static ExprResult
-calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
- ConstraintSatisfaction &Satisfaction,
- const ConstraintEvaluator &Evaluator);
-
-template <typename ConstraintEvaluator>
-static ExprResult
-calculateConstraintSatisfaction(Sema &S, const Expr *LHS,
- OverloadedOperatorKind Op, const Expr *RHS,
- ConstraintSatisfaction &Satisfaction,
- const ConstraintEvaluator &Evaluator) {
+static bool
+DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
+ const NamedDecl *Templ, const Expr *E,
+ const MultiLevelTemplateArgumentList &MLTAL) {
+ E->Profile(ID, S.Context, /*Canonical=*/true);
+ for (const auto &List : MLTAL)
+ for (const auto &TemplateArg : List.Args)
+ TemplateArg.Profile(ID, S.Context);
+
+ // Note that we have to do this with our own collection, because there are
+ // times where a constraint-expression check can cause us to need to evaluate
+ // other constriants that are unrelated, such as when evaluating a recovery
+ // expression, or when trying to determine the constexpr-ness of special
+ // members. Otherwise we could just use the
+ // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function.
+ if (S.SatisfactionStackContains(Templ, ID)) {
+ S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
+ << const_cast<Expr *>(E) << E->getSourceRange();
+ return true;
+ }
+
+ return false;
+}
+
+static ExprResult EvaluateAtomicConstraint(
+ Sema &S, const Expr *AtomicExpr, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
+ Sema::ReuseLambdaContextDecl);
+
+ // Atomic constraint - substitute arguments and check satisfaction.
+ ExprResult SubstitutedExpression;
+ {
+ TemplateDeductionInfo Info(TemplateNameLoc);
+ Sema::InstantiatingTemplate Inst(
+ S, AtomicExpr->getBeginLoc(),
+ Sema::InstantiatingTemplate::ConstraintSubstitution{},
+ // FIXME: improve const-correctness of InstantiatingTemplate
+ const_cast<NamedDecl *>(Template), Info, AtomicExpr->getSourceRange());
+ if (Inst.isInvalid())
+ return ExprError();
+
+ llvm::FoldingSetNodeID ID;
+ if (Template &&
+ DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
+ Satisfaction.IsSatisfied = false;
+ Satisfaction.ContainsErrors = true;
+ return ExprEmpty();
+ }
+
+ SatisfactionStackRAII StackRAII(S, Template, ID);
+
+ // We do not want error diagnostics escaping here.
+ Sema::SFINAETrap Trap(S);
+ SubstitutedExpression =
+ S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
+
+ if (SubstitutedExpression.isInvalid() || 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())
+ // A non-SFINAE error has occurred as a result of this
+ // substitution.
+ return ExprError();
+
+ PartialDiagnosticAt SubstDiag{SourceLocation(),
+ PartialDiagnostic::NullDiagnostic()};
+ Info.takeSFINAEDiagnostic(SubstDiag);
+ // FIXME: Concepts: This is an unfortunate consequence of there
+ // being no serialization code for PartialDiagnostics and the fact
+ // that serializing them would likely take a lot more storage than
+ // just storing them as strings. We would still like, in the
+ // future, to serialize the proper PartialDiagnostic as serializing
+ // it as a string defeats the purpose of the diagnostic mechanism.
+ SmallString<128> DiagString;
+ DiagString = ": ";
+ SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
+ unsigned MessageSize = DiagString.size();
+ char *Mem = new (S.Context) char[MessageSize];
+ memcpy(Mem, DiagString.c_str(), MessageSize);
+ Satisfaction.Details.emplace_back(
+ new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
+ SubstDiag.first, StringRef(Mem, MessageSize)});
+ Satisfaction.IsSatisfied = false;
+ return ExprEmpty();
+ }
+ }
+
+ if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
+ return ExprError();
+
+ // [temp.constr.atomic]p3: To determine if an atomic constraint is
+ // satisfied, the parameter mapping and template arguments are first
+ // substituted into its expression. If substitution results in an
+ // invalid type or expression, the constraint is not satisfied.
+ // Otherwise, the lvalue-to-rvalue conversion is performed if necessary,
+ // and E shall be a constant expression of type bool.
+ //
+ // Perform the L to R Value conversion if necessary. We do so for all
+ // non-PRValue categories, else we fail to extend the lifetime of
+ // temporaries, and that fails the constant expression check.
+ if (!SubstitutedExpression.get()->isPRValue())
+ SubstitutedExpression = ImplicitCastExpr::Create(
+ S.Context, SubstitutedExpression.get()->getType(), CK_LValueToRValue,
+ SubstitutedExpression.get(),
+ /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
+
+ return SubstitutedExpression;
+}
+
+std::optional<unsigned> static EvaluateFoldExpandedConstraintSize(
+ Sema &S, const CXXFoldExpr *FE, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
+
+ // We should ignore errors in the presence of packs of
diff erent size.
+ Sema::SFINAETrap Trap(S);
+
+ Expr *Pattern = FE->getPattern();
+
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+ bool Expand = true;
+ bool RetainExpansion = false;
+ std::optional<unsigned> OrigNumExpansions = FE->getNumExpansions(),
+ NumExpansions = OrigNumExpansions;
+ if (S.CheckParameterPacksForExpansion(
+ FE->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, MLTAL,
+ Expand, RetainExpansion, NumExpansions) ||
+ !Expand || RetainExpansion)
+ return std::nullopt;
+
+ if (NumExpansions && S.getLangOpts().BracketDepth < NumExpansions) {
+ S.Diag(FE->getEllipsisLoc(),
+ clang::diag::err_fold_expression_limit_exceeded)
+ << *NumExpansions << S.getLangOpts().BracketDepth
+ << FE->getSourceRange();
+ S.Diag(FE->getEllipsisLoc(), diag::note_bracket_depth);
+ return std::nullopt;
+ }
+ return NumExpansions;
+}
+
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const Expr *ConstraintExpr, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction);
+
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const Expr *LHS, OverloadedOperatorKind Op, const Expr *RHS,
+ const NamedDecl *Template, SourceLocation TemplateNameLoc,
+ const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
- ExprResult LHSRes =
- calculateConstraintSatisfaction(S, LHS, Satisfaction, Evaluator);
+ ExprResult LHSRes = calculateConstraintSatisfaction(
+ S, LHS, Template, TemplateNameLoc, MLTAL, Satisfaction);
if (LHSRes.isInvalid())
return ExprError();
@@ -218,8 +363,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *LHS,
// LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
return LHSRes;
- ExprResult RHSRes =
- calculateConstraintSatisfaction(S, RHS, Satisfaction, Evaluator);
+ ExprResult RHSRes = calculateConstraintSatisfaction(
+ S, RHS, Template, TemplateNameLoc, MLTAL, Satisfaction);
if (RHSRes.isInvalid())
return ExprError();
@@ -247,18 +392,17 @@ calculateConstraintSatisfaction(Sema &S, const Expr *LHS,
LHS->getBeginLoc(), FPOptionsOverride{});
}
-template <typename ConstraintEvaluator>
-static ExprResult
-calculateConstraintSatisfaction(Sema &S, const CXXFoldExpr *FE,
- ConstraintSatisfaction &Satisfaction,
- const ConstraintEvaluator &Evaluator) {
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const CXXFoldExpr *FE, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
bool Conjunction = FE->getOperator() == BinaryOperatorKind::BO_LAnd;
size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
ExprResult Out;
if (FE->isLeftFold() && FE->getInit()) {
- Out = calculateConstraintSatisfaction(S, FE->getInit(), Satisfaction,
- Evaluator);
+ Out = calculateConstraintSatisfaction(S, FE->getInit(), Template,
+ TemplateNameLoc, MLTAL, Satisfaction);
if (Out.isInvalid())
return ExprError();
@@ -269,14 +413,14 @@ calculateConstraintSatisfaction(Sema &S, const CXXFoldExpr *FE,
if (Conjunction != Satisfaction.IsSatisfied)
return Out;
}
- std::optional<unsigned> NumExpansions =
- Evaluator.EvaluateFoldExpandedConstraintSize(FE);
+ std::optional<unsigned> NumExpansions = EvaluateFoldExpandedConstraintSize(
+ S, FE, Template, TemplateNameLoc, MLTAL, Satisfaction);
if (!NumExpansions)
return ExprError();
for (unsigned I = 0; I < *NumExpansions; I++) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, I);
- ExprResult Res = calculateConstraintSatisfaction(S, FE->getPattern(),
- Satisfaction, Evaluator);
+ ExprResult Res = calculateConstraintSatisfaction(
+ S, FE->getPattern(), Template, TemplateNameLoc, MLTAL, Satisfaction);
if (Res.isInvalid())
return ExprError();
bool IsRHSSatisfied = Satisfaction.IsSatisfied;
@@ -298,8 +442,8 @@ calculateConstraintSatisfaction(Sema &S, const CXXFoldExpr *FE,
}
if (FE->isRightFold() && FE->getInit()) {
- ExprResult Res = calculateConstraintSatisfaction(S, FE->getInit(),
- Satisfaction, Evaluator);
+ ExprResult Res = calculateConstraintSatisfaction(
+ S, FE->getInit(), Template, TemplateNameLoc, MLTAL, Satisfaction);
if (Out.isInvalid())
return ExprError();
@@ -319,34 +463,37 @@ calculateConstraintSatisfaction(Sema &S, const CXXFoldExpr *FE,
return Out;
}
-template <typename ConstraintEvaluator>
-static ExprResult
-calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
- ConstraintSatisfaction &Satisfaction,
- const ConstraintEvaluator &Evaluator) {
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const Expr *ConstraintExpr, const NamedDecl *Template,
+ SourceLocation TemplateNameLoc, const MultiLevelTemplateArgumentList &MLTAL,
+ ConstraintSatisfaction &Satisfaction) {
ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
if (LogicalBinOp BO = ConstraintExpr)
return calculateConstraintSatisfaction(
- S, BO.getLHS(), BO.getOp(), BO.getRHS(), Satisfaction, Evaluator);
+ S, BO.getLHS(), BO.getOp(), BO.getRHS(), Template, TemplateNameLoc,
+ MLTAL, Satisfaction);
if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) {
// These aren't evaluated, so we don't care about cleanups, so we can just
// evaluate these as if the cleanups didn't exist.
- return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction,
- Evaluator);
+ return calculateConstraintSatisfaction(
+ S, C->getSubExpr(), Template, TemplateNameLoc, MLTAL, Satisfaction);
}
if (auto *FE = dyn_cast<CXXFoldExpr>(ConstraintExpr);
FE && S.getLangOpts().CPlusPlus26 &&
(FE->getOperator() == BinaryOperatorKind::BO_LAnd ||
FE->getOperator() == BinaryOperatorKind::BO_LOr)) {
- return calculateConstraintSatisfaction(S, FE, Satisfaction, Evaluator);
+ return calculateConstraintSatisfaction(S, FE, Template, TemplateNameLoc,
+ MLTAL, Satisfaction);
}
+ // FIXME: We should not treat ConceptSpecializationExpr as atomic constraints.
+
// An atomic constraint expression
- ExprResult SubstitutedAtomicExpr =
- Evaluator.EvaluateAtomicConstraint(ConstraintExpr);
+ ExprResult SubstitutedAtomicExpr = EvaluateAtomicConstraint(
+ S, ConstraintExpr, Template, TemplateNameLoc, MLTAL, Satisfaction);
if (SubstitutedAtomicExpr.isInvalid())
return ExprError();
@@ -405,165 +552,13 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
return SubstitutedAtomicExpr;
}
-static bool
-DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
- const NamedDecl *Templ, const Expr *E,
- const MultiLevelTemplateArgumentList &MLTAL) {
- E->Profile(ID, S.Context, /*Canonical=*/true);
- for (const auto &List : MLTAL)
- for (const auto &TemplateArg : List.Args)
- TemplateArg.Profile(ID, S.Context);
-
- // Note that we have to do this with our own collection, because there are
- // times where a constraint-expression check can cause us to need to evaluate
- // other constriants that are unrelated, such as when evaluating a recovery
- // expression, or when trying to determine the constexpr-ness of special
- // members. Otherwise we could just use the
- // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function.
- if (S.SatisfactionStackContains(Templ, ID)) {
- S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self)
- << const_cast<Expr *>(E) << E->getSourceRange();
- return true;
- }
-
- return false;
-}
-
static ExprResult calculateConstraintSatisfaction(
Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc,
const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction) {
- struct ConstraintEvaluator {
- Sema &S;
- const NamedDecl *Template;
- SourceLocation TemplateNameLoc;
- const MultiLevelTemplateArgumentList &MLTAL;
- ConstraintSatisfaction &Satisfaction;
-
- ExprResult EvaluateAtomicConstraint(const Expr *AtomicExpr) const {
- EnterExpressionEvaluationContext ConstantEvaluated(
- S, Sema::ExpressionEvaluationContext::ConstantEvaluated,
- Sema::ReuseLambdaContextDecl);
-
- // Atomic constraint - substitute arguments and check satisfaction.
- ExprResult SubstitutedExpression;
- {
- TemplateDeductionInfo Info(TemplateNameLoc);
- Sema::InstantiatingTemplate Inst(
- S, AtomicExpr->getBeginLoc(),
- Sema::InstantiatingTemplate::ConstraintSubstitution{},
- // FIXME: improve const-correctness of InstantiatingTemplate
- const_cast<NamedDecl *>(Template), Info,
- AtomicExpr->getSourceRange());
- if (Inst.isInvalid())
- return ExprError();
-
- llvm::FoldingSetNodeID ID;
- if (Template &&
- DiagRecursiveConstraintEval(S, ID, Template, AtomicExpr, MLTAL)) {
- Satisfaction.IsSatisfied = false;
- Satisfaction.ContainsErrors = true;
- return ExprEmpty();
- }
-
- SatisfactionStackRAII StackRAII(S, Template, ID);
-
- // We do not want error diagnostics escaping here.
- Sema::SFINAETrap Trap(S);
- SubstitutedExpression =
- S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL);
-
- if (SubstitutedExpression.isInvalid() || 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())
- // A non-SFINAE error has occurred as a result of this
- // substitution.
- return ExprError();
-
- PartialDiagnosticAt SubstDiag{SourceLocation(),
- PartialDiagnostic::NullDiagnostic()};
- Info.takeSFINAEDiagnostic(SubstDiag);
- // FIXME: Concepts: This is an unfortunate consequence of there
- // being no serialization code for PartialDiagnostics and the fact
- // that serializing them would likely take a lot more storage than
- // just storing them as strings. We would still like, in the
- // future, to serialize the proper PartialDiagnostic as serializing
- // it as a string defeats the purpose of the diagnostic mechanism.
- SmallString<128> DiagString;
- DiagString = ": ";
- SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString);
- unsigned MessageSize = DiagString.size();
- char *Mem = new (S.Context) char[MessageSize];
- memcpy(Mem, DiagString.c_str(), MessageSize);
- Satisfaction.Details.emplace_back(
- new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
- SubstDiag.first, StringRef(Mem, MessageSize)});
- Satisfaction.IsSatisfied = false;
- return ExprEmpty();
- }
- }
-
- if (!S.CheckConstraintExpression(SubstitutedExpression.get()))
- return ExprError();
-
- // [temp.constr.atomic]p3: To determine if an atomic constraint is
- // satisfied, the parameter mapping and template arguments are first
- // substituted into its expression. If substitution results in an
- // invalid type or expression, the constraint is not satisfied.
- // Otherwise, the lvalue-to-rvalue conversion is performed if necessary,
- // and E shall be a constant expression of type bool.
- //
- // Perform the L to R Value conversion if necessary. We do so for all
- // non-PRValue categories, else we fail to extend the lifetime of
- // temporaries, and that fails the constant expression check.
- if (!SubstitutedExpression.get()->isPRValue())
- SubstitutedExpression = ImplicitCastExpr::Create(
- S.Context, SubstitutedExpression.get()->getType(),
- CK_LValueToRValue, SubstitutedExpression.get(),
- /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride());
-
- return SubstitutedExpression;
- }
-
- std::optional<unsigned>
- EvaluateFoldExpandedConstraintSize(const CXXFoldExpr *FE) const {
-
- // We should ignore errors in the presence of packs of
diff erent size.
- Sema::SFINAETrap Trap(S);
-
- Expr *Pattern = FE->getPattern();
-
- SmallVector<UnexpandedParameterPack, 2> Unexpanded;
- S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
- assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
- bool Expand = true;
- bool RetainExpansion = false;
- std::optional<unsigned> OrigNumExpansions = FE->getNumExpansions(),
- NumExpansions = OrigNumExpansions;
- if (S.CheckParameterPacksForExpansion(
- FE->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded,
- MLTAL, Expand, RetainExpansion, NumExpansions) ||
- !Expand || RetainExpansion)
- return std::nullopt;
-
- if (NumExpansions && S.getLangOpts().BracketDepth < NumExpansions) {
- S.Diag(FE->getEllipsisLoc(),
- clang::diag::err_fold_expression_limit_exceeded)
- << *NumExpansions << S.getLangOpts().BracketDepth
- << FE->getSourceRange();
- S.Diag(FE->getEllipsisLoc(), diag::note_bracket_depth);
- return std::nullopt;
- }
- return NumExpansions;
- }
- };
-
- return calculateConstraintSatisfaction(
- S, ConstraintExpr, Satisfaction,
- ConstraintEvaluator{S, Template, TemplateNameLoc, MLTAL, Satisfaction});
+ return calculateConstraintSatisfaction(S, ConstraintExpr, Template,
+ TemplateNameLoc, MLTAL, Satisfaction);
}
static bool CheckConstraintSatisfaction(
@@ -688,23 +683,17 @@ bool Sema::CheckConstraintSatisfaction(
return false;
}
-bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr,
- ConstraintSatisfaction &Satisfaction) {
+bool Sema::CheckConstraintSatisfaction(
+ const ConceptSpecializationExpr *ConstraintExpr,
+ ConstraintSatisfaction &Satisfaction) {
- struct ConstraintEvaluator {
- Sema &S;
- ExprResult EvaluateAtomicConstraint(const Expr *AtomicExpr) const {
- return S.PerformContextuallyConvertToBool(const_cast<Expr *>(AtomicExpr));
- }
+ MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(),
+ ConstraintExpr->getTemplateArguments(),
+ true);
- std::optional<unsigned>
- EvaluateFoldExpandedConstraintSize(const CXXFoldExpr *FE) const {
- return 0;
- }
- };
-
- return calculateConstraintSatisfaction(*this, ConstraintExpr, Satisfaction,
- ConstraintEvaluator{*this})
+ return calculateConstraintSatisfaction(
+ *this, ConstraintExpr, ConstraintExpr->getNamedConcept(),
+ ConstraintExpr->getConceptNameLoc(), MLTAL, Satisfaction)
.isInvalid();
}
@@ -1183,8 +1172,7 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints(
LambdaScopeForCallOperatorInstantiationRAII LambdaScope(
*this, const_cast<FunctionDecl *>(Decl), *MLTAL, Scope);
- llvm::SmallVector<Expr *, 1> Converted;
- return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL,
+ return CheckConstraintSatisfaction(Template, TemplateAC, *MLTAL,
PointOfInstantiation, Satisfaction);
}
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index aae3135772b7f..2142582adf6e9 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -17551,16 +17551,17 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
std::string InnerCondDescription;
std::tie(InnerCond, InnerCondDescription) =
findFailedBooleanCondition(Converted.get());
- if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) {
+ if (const auto *ConceptIDExpr =
+ dyn_cast_or_null<ConceptSpecializationExpr>(InnerCond)) {
// Drill down into concept specialization expressions to see why they
// weren't satisfied.
Diag(AssertExpr->getBeginLoc(), diag::err_static_assert_failed)
<< !HasMessage << Msg.str() << AssertExpr->getSourceRange();
ConstraintSatisfaction Satisfaction;
- if (!CheckConstraintSatisfaction(InnerCond, Satisfaction))
+ if (!CheckConstraintSatisfaction(ConceptIDExpr, Satisfaction))
DiagnoseUnsatisfiedConstraint(Satisfaction);
- } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond)
- && !isa<IntegerLiteral>(InnerCond)) {
+ } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) &&
+ !isa<IntegerLiteral>(InnerCond)) {
Diag(InnerCond->getBeginLoc(),
diag::err_static_assert_requirement_failed)
<< InnerCondDescription << !HasMessage << Msg.str()
More information about the cfe-commits
mailing list