rsmith added inline comments.
================ Comment at: clang/lib/AST/ExprConstant.cpp:711 + + /// Evaluate as a constant expression, as per C++11-and-later constexpr + /// rules. Stop if we find that the expression is not a constant ---------------- jyknight wrote: > rsmith wrote: > > This is not the intent. The evaluator uses the rules of the current > > language mode. However, it doesn't enforce the C and C++98 syntactic > > restrictions on what can appear in a constant expression, because it turns > > out to be cleaner to check those separately rather than to interleave them > > with evaluation. > > > > We should probably document this as evaluating following the evaluation > > (but not syntactic) constant expression rules of the current language mode. > I'm not really sure what you mean to distinguish between C/C++98 "evaluation > constant expression rules" and the definition of a C/C++98 ICE? > > Perhaps you mean that if evaluation succeeds, it will have produced a value > consistent with the rules of the current language, but that it may not > produce the diagnostics in all cases it ought to? > > AFAICT, the evaluator is designed to emit diagnostics only for the C++11 (and > later) constant expression rules, as well as for inability to evaluate. The > diagnostic notes are usually dropped on the floor in C++98 and C modes, as > only "fold" is typically used there -- along with the separate CheckICE to > produce warnings. > > I believe the only place the diagnostics were being actually emitted in > pre-c++11 modes is for the diagnose_if and enable_if attributes' "potential > constant expression" check. And there it really seems to me to be using the > c++11 evaluation semantics. > > The existence of isCXX11ConstantExpr suggests an intent for the function to > provide the C++11 rules, as well, no? > > > Perhaps you mean that if evaluation succeeds, it will have produced a value > consistent with the rules of the current language, but that it may not > produce the diagnostics in all cases it ought to? The concern I have with this comment is that it describes a happenstance of implementation rather than the intent. The intent is certainly *not* that we will use the C++11 rules when calling this in C++98 mode, but it just so happens that there are no interesting differences there right now. Looking at this another way, the fact that we only guarantee to produce "not a constant expression because" notes in C++11 onwards is unrelated to the evaluation mode. Rather, the reason for that is instead because all the validity / ICE checking in other language modes is based on the syntactic form of the expression (and is checked separately as a result). As a concrete suggestion, how about something like: "Evaluate as a constant expression. Stop if we find that the expression is not a constant expression. Note that this doesn't enforce the syntactic ICE requirements of C and C++98." ================ Comment at: clang/lib/AST/ExprConstant.cpp:952 + /// with diagnostics. + bool keepEvaluatingAfterNote() { switch (EvalMode) { ---------------- jyknight wrote: > rsmith wrote: > > "Note" is beside the point here. We should be talking about non-constant > > expressions; that's what matters. > Renamed to keepEvaluatingAfterNonConstexpr, updated comment. Capitalize as "...NonConstExpr" instead, since this is just an abbreviation of the term "constant expression", not C++11's notion of "constexpr". (I'd also lengthen this to "...NonConstantExpr" or "...NonConstantExpression" to further clarify.) ================ Comment at: clang/lib/AST/ExprConstant.cpp:1440-1444 + if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base)) { Designator.addDeclUnchecked(D, Virtual); + return true; + } + return Info.keepEvaluatingAfterNote(); ---------------- jyknight wrote: > rsmith wrote: > > `checkSubobject` should return `false` if it produced a diagnostic that > > should cause evaluation to halt; this call to `keepEvaluatingAfterNote` > > should not be necessary. (And likewise below.) > Are you sure? > > Today, checkSubobject returns false if it sees something "invalid" -- and the > callers seem to depend on that -- but invalid subobject designators are still > allowed during evaluation in fold mode. > > E.g., this is valid in C: > `struct Foo { int x[]; }; struct Foo f; int *g = f.x;` > > But, in C++, `constexpr int *g = f.x;` is an error, diagnosing > note_constexpr_unsupported_unsized_array. > > All the LValue code, with its mutable "Result" state, and carrying of a > couple different "Invalid" bits off on the side, is really rather confusing! What I mean is that you should change the code to make what I said be true, if necessary. It's the callee's responsibility to say whether we hit something we can't evaluate past. The caller should not be guessing that the only reason that `checkSubobject` can fail is due to a `CCEDiag` -- if `checkSubobject` fails with an `FFDiag`, this will sometimes return `true`, which would be wrong. Here's how I'd look at it: a `false` value is a token that indicates that someone has produced a diagnostic whose severity is such that we don't need to keep evaluating. Once that happens, we don't need to re-check whether to keep evaluating, because we've already been told that we shouldn't, and we just need to propagate that fact to our caller. ================ Comment at: clang/lib/AST/ExprConstant.cpp:710 + // EM_PotentialConstantExpressionUnevaluated as a duplicate). This will + // be somewhat tricky to change, because LLVM currently verifies that an + // expression is a constant expression (possibly strictly with ---------------- LLVM -> Clang (or "we" or similar) ================ Comment at: clang/lib/AST/ExprConstant.cpp:723 + /// Fold the expression to a constant, using any techniques we can. Stop + /// if we hit a side-effect that we can't model, or undefined behavior. EM_ConstantFold, ---------------- Do we now guarantee to stop on UB in this mode? We didn't appear to do so previously. (Particularly, we'd evaluate past signed overflow and take the 2's complement value.) ================ Comment at: clang/lib/AST/ExprConstant.cpp:956 + /// expression which is not a constant expression? If this returns true, + /// then the evaluation will be successful if and only no diagnostics are + /// emitted. If it returns false, evaluation can succeed with diagnostics. ---------------- only no -> only if no ================ Comment at: clang/lib/AST/ExprConstant.cpp:1198-1200 + if (!Info.keepEvaluatingAfterNonConstexpr()) + return false; + return true; ---------------- Simplify to `return Info.keepEvaluating...();` ================ Comment at: clang/lib/AST/ExprConstant.cpp:2527-2529 + if (!LVal.adjustOffsetAndIndex(Info, E, Adjustment, SizeOfPointee)) + return false; return true; ---------------- Simplify to `return LVal.adjust[...]` ================ Comment at: clang/lib/AST/ExprConstant.cpp:7438 + return VisitIgnoredBaseExpression(E->getBase()); } ---------------- Nit: drop the braces here. ================ Comment at: clang/lib/AST/ExprConstant.cpp:11490-11492 + // _is_ a constant expression. (Note: the above applies in + // EM_ConstantExpression mode, which we use here, but not in, + // e.g. EM_ConstantFold or others.) ---------------- I don't believe the parenthetical is true: in C++11 or later, we should always get a note if and only if the expression is not a constant expression, regardless of evaluation mode. Instead, I think the thing you're highlighting here is that the return value from `EvaluateAsRValue` does not indicate whether the expression is a constant expression unless the evaluation mode is `EM_ConstantExpression`. ================ Comment at: clang/lib/AST/ExprConstant.cpp:11495-11496 + if (!Diags.empty()) { - IsConstExpr = false; if (Loc) *Loc = Diags[0].first; } ---------------- Combine these two `if`s. https://reviews.llvm.org/D52939 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits