[PATCH] D84637: [AST] Enhance the const expression evaluator to support error-dependent exprs.

Richard Smith - zygoloid via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 21 11:43:56 PDT 2020


rsmith added a comment.

There are a couple of cases where you're returning `EvalStmtResult` from a function with a `bool` return type, that I'd like to see fixed before this lands.

All the other comments are directed towards producing more precise behavior when evaluating a function containing errors / value-dependent constructs. I don't think there's any need to block fixing the crasher here on improving the diagnostics, so I'm happy if you ignore these and commit as-is (other than fixing the return type issue), but I think we'll want to look at these diagnostic improvements at some point.



================
Comment at: clang/lib/AST/ExprConstant.cpp:4585
 
 static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
   // We don't need to evaluate the initializer for a static local.
----------------
I think it would be slightly better if the dependent cases in this function returned `noteSideEffect()` instead of `false`.


================
Comment at: clang/lib/AST/ExprConstant.cpp:4613-4625
 static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
   bool OK = true;
 
   if (const VarDecl *VD = dyn_cast<VarDecl>(D))
     OK &= EvaluateVarDecl(Info, VD);
 
   if (const DecompositionDecl *DD = dyn_cast<DecompositionDecl>(D))
----------------
This function should bail out as soon as it sees an error. Otherwise, I think
```
constexpr void f() { int a = error(), b = a; }
```
... will to produce a hard error when evaluating `b`, because its initializer appears to read from an uninitialized variable.


================
Comment at: clang/lib/AST/ExprConstant.cpp:4627
 
+static EvalStmtResult EvaluateDependentExpr(const Expr *E, EvalInfo &Info) {
+  assert(E->isValueDependent());
----------------
Given the number of places below that seem to need to branch on the return value rather than returning it directly, and the use from contexts other than statement evaluation, I think it might be better for this function to return `bool`.


================
Comment at: clang/lib/AST/ExprConstant.cpp:4867
+        if (Inc->isValueDependent())
+          return EvaluateDependentExpr(Inc, Info);
         FullExpressionRAII IncScope(Info);
----------------
If this returns `ESR_Succeeded`, we should keep going rather than returning that value. Otherwise we'll do the wrong thing for cases like:

```
constexpr bool f() {
  for (int n = 0; ; ++n, error()) { if (n == 1) return true; }
  throw "bad";
}
```

... because evaluation of the `for` loop (but not the enclosing function) will terminate at the value-dependent increment expression, so we'll think that all evaluations of this function unconditionally throw.


================
Comment at: clang/lib/AST/ExprConstant.cpp:5026
+      if (DS->getCond()->isValueDependent())
+        return EvaluateDependentExpr(DS->getCond(), Info);
       FullExpressionRAII CondScope(Info);
----------------
If the condition is value-dependent, I think we should return `ESR_Failed` here: we don't know whether to keep going or terminate the loop, and either answer will be wrong in some cases.


================
Comment at: clang/lib/AST/ExprConstant.cpp:5064
+        if (Inc->isValueDependent())
+          return EvaluateDependentExpr(Inc, Info);
         FullExpressionRAII IncScope(Info);
----------------
As above, I think we need to keep going on `ESR_Succeeded` here.


================
Comment at: clang/lib/AST/ExprConstant.cpp:5116
+        if (FS->getCond()->isValueDependent())
+          return EvaluateDependentExpr(FS->getCond(), Info);
         bool Continue = true;
----------------
We should return `ESR_Failed` unconditionally here, because we don't know which statement to execute next.


================
Comment at: clang/lib/AST/ExprConstant.cpp:5142
+      if (FS->getInc()->isValueDependent())
+        return EvaluateDependentExpr(FS->getInc(), Info);
       // Increment: ++__begin
----------------
As above, I think we need to keep going on `ESR_Succeeded` here.


================
Comment at: clang/lib/AST/ExprConstant.cpp:5896-5898
+    if ((*I)->getInit()->isValueDependent())
+      return EvaluateDependentExpr((*I)->getInit(), Info);
     {
----------------
This is returning an `EvalStmtResult` from a function with a `bool` return type. It'd also be a bit more precise to keep going after a value-dependent expression here, so that we can diagnose non-constant constructs in the body after a typo in the mem-initializer list.


================
Comment at: clang/lib/AST/ExprConstant.cpp:6042-6043
     const Expr *Init = I->getInit();
+    if (Init->isValueDependent())
+      return EvaluateDependentExpr(Init, Info);
     ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent,
----------------
Similarly, it'd be a bit more precise to keep going if `EvaluateDependentExpr` says it succeeded.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D84637/new/

https://reviews.llvm.org/D84637



More information about the cfe-commits mailing list