[clang] [Clang][C++26] Implement "Ordering of constraints involving fold expressions (PR #98160)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 9 09:07:05 PDT 2024
================
@@ -177,77 +178,180 @@ struct SatisfactionStackRAII {
};
} // namespace
-template <typename AtomicEvaluator>
+template <typename ConstraintEvaluator>
static ExprResult
calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr,
ConstraintSatisfaction &Satisfaction,
- AtomicEvaluator &&Evaluator) {
- ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts();
+ ConstraintEvaluator &&Evaluator);
- if (LogicalBinOp BO = ConstraintExpr) {
- size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
- ExprResult LHSRes = calculateConstraintSatisfaction(
- S, BO.getLHS(), Satisfaction, Evaluator);
+template <typename ConstraintEvaluator>
+static ExprResult calculateConstraintSatisfaction(
+ Sema &S, const Expr *LHS, OverloadedOperatorKind Op, const Expr *RHS,
+ ConstraintSatisfaction &Satisfaction, ConstraintEvaluator &Evaluator) {
+ size_t EffectiveDetailEndIndex = Satisfaction.Details.size();
- if (LHSRes.isInvalid())
- return ExprError();
+ ExprResult LHSRes =
+ calculateConstraintSatisfaction(S, LHS, Satisfaction, Evaluator);
- bool IsLHSSatisfied = Satisfaction.IsSatisfied;
+ if (LHSRes.isInvalid())
+ return ExprError();
- if (BO.isOr() && IsLHSSatisfied)
- // [temp.constr.op] p3
- // A disjunction is a constraint taking two operands. To determine if
- // a disjunction is satisfied, the satisfaction of the first operand
- // is checked. If that is satisfied, the disjunction is satisfied.
- // Otherwise, the disjunction is satisfied if and only if the second
- // operand is satisfied.
- // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
- return LHSRes;
-
- if (BO.isAnd() && !IsLHSSatisfied)
- // [temp.constr.op] p2
- // A conjunction is a constraint taking two operands. To determine if
- // a conjunction is satisfied, the satisfaction of the first operand
- // is checked. If that is not satisfied, the conjunction is not
- // satisfied. Otherwise, the conjunction is satisfied if and only if
- // the second operand is satisfied.
- // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
- return LHSRes;
-
- ExprResult RHSRes = calculateConstraintSatisfaction(
- S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator));
- if (RHSRes.isInvalid())
- return ExprError();
+ bool IsLHSSatisfied = Satisfaction.IsSatisfied;
+
+ if (Op == clang::OO_PipePipe && IsLHSSatisfied)
+ // [temp.constr.op] p3
+ // A disjunction is a constraint taking two operands. To determine if
+ // a disjunction is satisfied, the satisfaction of the first operand
+ // is checked. If that is satisfied, the disjunction is satisfied.
+ // Otherwise, the disjunction is satisfied if and only if the second
+ // operand is satisfied.
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
+
+ if (Op == clang::OO_AmpAmp && !IsLHSSatisfied)
+ // [temp.constr.op] p2
+ // A conjunction is a constraint taking two operands. To determine if
+ // a conjunction is satisfied, the satisfaction of the first operand
+ // is checked. If that is not satisfied, the conjunction is not
+ // satisfied. Otherwise, the conjunction is satisfied if and only if
+ // the second operand is satisfied.
+ // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp.
+ return LHSRes;
+
+ ExprResult RHSRes = calculateConstraintSatisfaction(
+ S, RHS, Satisfaction, std::forward<ConstraintEvaluator>(Evaluator));
+ if (RHSRes.isInvalid())
+ return ExprError();
+
+ bool IsRHSSatisfied = Satisfaction.IsSatisfied;
+ // Current implementation adds diagnostic information about the falsity
+ // of each false atomic constraint expression when it evaluates them.
+ // When the evaluation results to `false || true`, the information
+ // generated during the evaluation of left-hand side is meaningless
+ // because the whole expression evaluates to true.
+ // The following code removes the irrelevant diagnostic information.
+ // FIXME: We should probably delay the addition of diagnostic information
+ // until we know the entire expression is false.
+ if (Op == clang::OO_PipePipe && IsRHSSatisfied) {
+ auto EffectiveDetailEnd = Satisfaction.Details.begin();
+ std::advance(EffectiveDetailEnd, EffectiveDetailEndIndex);
+ Satisfaction.Details.erase(EffectiveDetailEnd, Satisfaction.Details.end());
+ }
+ if (!LHSRes.isUsable() || !RHSRes.isUsable())
+ return ExprEmpty();
+
+ return BinaryOperator::Create(S.Context, LHSRes.get(), RHSRes.get(),
+ BinaryOperator::getOverloadedOpcode(Op),
+ S.Context.BoolTy, VK_PRValue, OK_Ordinary,
+ LHS->getBeginLoc(), FPOptionsOverride{});
+}
+
+template <typename ConstraintEvaluator>
+static ExprResult
+calculateConstraintSatisfaction(Sema &S, const CXXFoldExpr *FE,
+ ConstraintSatisfaction &Satisfaction,
+ ConstraintEvaluator &&Evaluator) {
+ 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);
+ if (Out.isInvalid())
+ return ExprError();
+ bool IsLHSSatisfied = Satisfaction.IsSatisfied;
+ if (Conjunction && !IsLHSSatisfied) {
+ return Out;
+ }
+ if (!Conjunction && IsLHSSatisfied) {
+ return Out;
+ }
+ }
+ std::optional<unsigned> NumExpansions =
+ Evaluator.EvaluateFoldExpandedConstraintSize(FE);
+ if (!NumExpansions)
+ return ExprError();
+ for (unsigned I = 0; I < *NumExpansions; I++) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(S, I);
+ ExprResult Res = calculateConstraintSatisfaction(S, FE->getPattern(),
+ Satisfaction, Evaluator);
+ if (Res.isInvalid())
+ return ExprError();
bool IsRHSSatisfied = Satisfaction.IsSatisfied;
- // Current implementation adds diagnostic information about the falsity
- // of each false atomic constraint expression when it evaluates them.
- // When the evaluation results to `false || true`, the information
- // generated during the evaluation of left-hand side is meaningless
- // because the whole expression evaluates to true.
- // The following code removes the irrelevant diagnostic information.
- // FIXME: We should probably delay the addition of diagnostic information
- // until we know the entire expression is false.
- if (BO.isOr() && IsRHSSatisfied) {
+ if (!Conjunction && IsRHSSatisfied) {
auto EffectiveDetailEnd = Satisfaction.Details.begin();
std::advance(EffectiveDetailEnd, EffectiveDetailEndIndex);
Satisfaction.Details.erase(EffectiveDetailEnd,
Satisfaction.Details.end());
}
+ if (Out.isUnset())
+ Out = Res;
+ else if (!Res.isUnset()) {
+ Out = BinaryOperator::Create(
+ S.Context, Out.get(), Res.get(), FE->getOperator(), S.Context.BoolTy,
+ VK_PRValue, OK_Ordinary, FE->getBeginLoc(), FPOptionsOverride{});
+ }
+ if (Conjunction && !IsRHSSatisfied)
+ return Out;
+ if (!Conjunction && IsRHSSatisfied)
+ return Out;
----------------
AaronBallman wrote:
```suggestion
if (Conjunction != IsRHSSatisfied)
return Out;
```
https://github.com/llvm/llvm-project/pull/98160
More information about the cfe-commits
mailing list