kimgr added a comment.

I have now convinced myself that including `FullExpr` in 
`skipImplicitTemporary` gives an improvement in `consteval` diagnostics. But 
I'm still not sure why. Motivating example, derived from cxx2a-consteval.cpp:

  struct A {
    int *p = new int(42);
    consteval A ret_a() const {
        return A{};
    }
  };
  
  consteval const A &to_lvalue_ref(const A &&a) {
    return a;
  }
  
  void test() {
    constexpr A a{nullptr};
  
    // error: call to consteval function 'A::ret_a' is not a constant expression
    // { (void)a.ret_a(); }
  
    // error: call to consteval function 'to_lvalue_ref' is not a constant 
expression
    // { (void)to_lvalue_ref(A{}); }
  
    // error: call to consteval function 'to_lvalue_ref' is not a constant 
expression
    // but should probably also raise
    // error: call to consteval function 'A::ret_a' is not a constant expression
    { (void)to_lvalue_ref(a.ret_a()); }
  }

It's interesting to experiment with these one by one

- `A::ret_a` returns a new A, whose constructor does heap allocation; no 
consteval possible
- `to_lvalue_ref` attempts to return a reference to a temporary; no consteval 
possible

Composing the two as in the last example, it seems to me, should print both 
diagnostics. Mainline Clang doesn't, but changing `skipImplicitTemporary` to 
also skip `FullExpr`s does (also allowing removal of all `IgnoreImplicit` from 
`getSubExprAsWritten` and `getConversionFunction`).

It seems intuitively right to me. I'm just a little peeved that I can't figure 
out the connection between the diagnostic emission and `skipImplicitTemporary`.



================
Comment at: clang/lib/AST/Expr.cpp:1946-1947
   for (const CastExpr *E = this; E; E = dyn_cast<ImplicitCastExpr>(SubExpr)) {
     SubExpr = skipImplicitTemporary(E->getSubExpr());
+    SubExpr = SubExpr->IgnoreImplicit();
 
----------------
davrec wrote:
> aaron.ballman wrote:
> > `IgnoreImplicit()` calls `IgnoreImplicitSingleStep()` eventually, and that 
> > call does the same work as `skipImplicitTemporary()`, so I think the end 
> > result here should be the same.
> As I look at this a second time, I just realized...calling IgnoreImplicit 
> here mean that the loop only ever runs one iteration, since IgnoreImplicit 
> presumably skips over ImplicitCastExprs.  While I liked how Kim did revision 
> initially because it seemed to handle the constructor conversions similarly 
> to their handling of getSubExprAsWritten() above, now I think something 
> different is needed here.
> 
> Proposed alternative:
> Right now skipIimplicitTemporary does what IgnoreImplicit does *except* skip 
> over a) ImplicitCastExprs and b) FullExprs (= ConstantExprs or 
> ExprWithCleanups).
> 
> Kim has identified that we need to skip over at least ConstantExprs at least 
> in this case (i.e. the most conservative possible fix would be to skip over 
> ConstantExprs just before the cast in line 1950).
> 
> But perhaps the better solution, to forestall future bugs, is to skip over 
> FullExprs in skipImplicitTemporary, so that it skips over everything 
> IgnoreImplicit does except ImplicitCastExprs.  (And, some documentation 
> should be added to `skipImplicitTemporary` to that effect, to aid future 
> maintenance.)
> 
> I can't see offhand how the other uses of skipImplicitTemporary would be 
> negatively affected by additionally skipping over FullExprs.
> 
> Aaron what do you think?  Kim can you verify this alternative would also 
> solve the problem without breaking any tests?
> 
@aaron.ballman Just removing the `skipImplicitTemporary` line is probably not 
going to work, since that's the first time `SubExpr` is assigned a 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D117391

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to