================ @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits