[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-04-07 Thread Haojian Wu via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG041080c24735: [AST] Fix a crash on invalid constexpr 
Ctorinitializer when building… (authored by hokein).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/invalid-constructor-init.cpp


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {
+  int Y;
+  constexpr X() // expected-error {{constexpr constructor never produces}}
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+constexpr int Z = X().Y; // expected-error {{constexpr variable 'Z' must be 
initialized by a constant expression}}
+
+struct X2 {
+  int Y = foo();// expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant 
expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a 
constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int)
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+  // no bogus "delegation cycle" diagnostic
+  CycleDelegate(float) : CycleDelegate(1) {}
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4976,6 +4976,13 @@
 return false;
   }
 
+  if (const auto *CtorDecl = dyn_cast_or_null(Definition)) 
{
+for (const auto *InitExpr : CtorDecl->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
+
   // Can we evaluate this function call?
   if (Definition && Definition->isConstexpr() && Body)
 return true;
@@ -14709,6 +14716,15 @@
   if (FD->isDependentContext())
 return true;
 
+  // Bail out if a constexpr constructor has an initializer that contains an
+  // error. We deliberately don't produce a diagnostic, as we have produced a
+  // relevant diagnostic when parsing the error initializer.
+  if (const auto *Ctor = dyn_cast(FD)) {
+for (const auto *InitExpr : Ctor->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
   Expr::EvalStatus Status;
   Status.Diag = &Diags;
 


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {
+  int Y;
+  constexpr X() // expected-error {{constexpr constructor never produces}}
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+constexpr int Z = X().Y; // expected-error {{constexpr variable 'Z' must be initialized by a constant expression}}
+
+struct X2 {
+  int Y = foo();// expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int)
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+  // no bogus "delegation cycle" diagnostic
+  CycleDelegate(float) : CycleDelegate(1) {}
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4976,6 +4976,13 @@
 return false;
   }
 
+  if (const auto *CtorDecl = dyn_cast_or_null(Definition)) {
+for (const auto *InitExpr : CtorDecl->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
+
   // Can we evaluate this function call?
   if (Definition && Definition->isConstexpr() && Body)
 return true;
@@ -14709,6 +14716,15 @@
   if (FD->isDependentContext())
 return true;
 
+  // Bail out if a constexpr constructor has an initializer that contains an
+  // error. We deliberately don't produce a diagnostic, as we have produced a
+  // relevant diagnostic when parsing the error initializer.
+  if (const auto *Ctor = dyn_cast(FD)) {
+for (const auto *InitExpr : Ctor->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
   Expr::EvalStatus Status;
   Status.Diag = &Diags;
 
___
cfe-commits mailing list
cfe-commits@lists

[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-04-02 Thread Haojian Wu via Phabricator via cfe-commits
hokein updated this revision to Diff 254525.
hokein added a comment.

remove accident change.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/invalid-constructor-init.cpp


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {
+  int Y;
+  constexpr X() // expected-error {{constexpr constructor never produces}}
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+constexpr int Z = X().Y; // expected-error {{constexpr variable 'Z' must be 
initialized by a constant expression}}
+
+struct X2 {
+  int Y = foo();// expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant 
expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a 
constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int)
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+  // no bogus "delegation cycle" diagnostic
+  CycleDelegate(float) : CycleDelegate(1) {}
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4975,6 +4975,13 @@
 return false;
   }
 
+  if (const auto *CtorDecl = dyn_cast_or_null(Definition)) 
{
+for (const auto *InitExpr : CtorDecl->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
+
   // Can we evaluate this function call?
   if (Definition && Definition->isConstexpr() && Body)
 return true;
@@ -14736,6 +14743,15 @@
   if (FD->isDependentContext())
 return true;
 
+  // Bail out if a constexpr constructor has an initializer that contains an
+  // error. We deliberately don't produce a diagnostic, as we have produced a
+  // relevant diagnostic when parsing the error initializer.
+  if (const auto *Ctor = dyn_cast(FD)) {
+for (const auto *InitExpr : Ctor->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
   Expr::EvalStatus Status;
   Status.Diag = &Diags;
 


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {
+  int Y;
+  constexpr X() // expected-error {{constexpr constructor never produces}}
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+constexpr int Z = X().Y; // expected-error {{constexpr variable 'Z' must be initialized by a constant expression}}
+
+struct X2 {
+  int Y = foo();// expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int)
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+  // no bogus "delegation cycle" diagnostic
+  CycleDelegate(float) : CycleDelegate(1) {}
+};
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4975,6 +4975,13 @@
 return false;
   }
 
+  if (const auto *CtorDecl = dyn_cast_or_null(Definition)) {
+for (const auto *InitExpr : CtorDecl->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
+
   // Can we evaluate this function call?
   if (Definition && Definition->isConstexpr() && Body)
 return true;
@@ -14736,6 +14743,15 @@
   if (FD->isDependentContext())
 return true;
 
+  // Bail out if a constexpr constructor has an initializer that contains an
+  // error. We deliberately don't produce a diagnostic, as we have produced a
+  // relevant diagnostic when parsing the error initializer.
+  if (const auto *Ctor = dyn_cast(FD)) {
+for (const auto *InitExpr : Ctor->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
   Expr::EvalStatus Status;
   Status.Diag = &Diags;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-04-01 Thread Haojian Wu via Phabricator via cfe-commits
hokein updated this revision to Diff 254170.
hokein added a comment.

refine the fix based on the comment:

now constexpr ctor with error initializers is still a valid decl but not
constant-evaluate.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/test/SemaCXX/invalid-constructor-init.cpp


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {
+  int Y;
+  constexpr X() // expected-error {{constexpr constructor never produces}}
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+constexpr int Z = X().Y; // expected-error {{constexpr variable 'Z' must be 
initialized by a constant expression}}
+
+struct X2 {
+  int Y = foo();// expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant 
expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a 
constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int)
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+  // no bogus "delegation cycle" diagnostic
+  CycleDelegate(float) : CycleDelegate(1) {}
+};
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -45,6 +45,7 @@
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Support/Casting.h"
 #include 
 #include 
 #include 
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4975,6 +4975,13 @@
 return false;
   }
 
+  if (const auto *CtorDecl = dyn_cast_or_null(Definition)) 
{
+for (const auto *InitExpr : CtorDecl->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
+
   // Can we evaluate this function call?
   if (Definition && Definition->isConstexpr() && Body)
 return true;
@@ -14736,6 +14743,15 @@
   if (FD->isDependentContext())
 return true;
 
+  // Bail out if a constexpr constructor has an initializer that contains an
+  // error. We deliberately don't produce a diagnostic, as we have produced a
+  // relevant diagnostic when parsing the error initializer.
+  if (const auto *Ctor = dyn_cast(FD)) {
+for (const auto *InitExpr : Ctor->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
   Expr::EvalStatus Status;
   Status.Diag = &Diags;
 


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {
+  int Y;
+  constexpr X() // expected-error {{constexpr constructor never produces}}
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+constexpr int Z = X().Y; // expected-error {{constexpr variable 'Z' must be initialized by a constant expression}}
+
+struct X2 {
+  int Y = foo();// expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int)
+  : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+  // no bogus "delegation cycle" diagnostic
+  CycleDelegate(float) : CycleDelegate(1) {}
+};
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -45,6 +45,7 @@
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Support/Casting.h"
 #include 
 #include 
 #include 
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4975,6 +4975,13 @@
 return false;
   }
 
+  if (const auto *CtorDecl = dyn_cast_or_null(Definition)) {
+for (const auto *InitExpr : CtorDecl->inits()) {
+  if (InitExpr->getInit() && InitExpr->getInit()->containsErrors())
+return false;
+}
+  }
+
   // Can we evaluate t

[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-04-01 Thread Sam McCall via Phabricator via cfe-commits
sammccall added inline comments.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:5005
+if (Member->getInit() && Member->getInit()->containsErrors())
+  Constructor->setInvalidDecl();
 if (Member->isBaseInitializer())

hokein wrote:
> rsmith wrote:
> > rsmith wrote:
> > > This is inappropriate. The "invalid" bit on a declaration indicates 
> > > whether the declaration is invalid, not whether the definition is invalid.
> > > 
> > > What we should do is add a "contains errors" bit to `Stmt`, and mark the 
> > > function body as containing errors if it has an initializer that contains 
> > > an error.
> > As an example of why this distinction matters: the "contains errors" bit 
> > indicates whether external users of the declaration should ignore it / 
> > suppress errors on it, or whether they can still treat it as a regular 
> > declaration. It's not ideal for an error in the body of a function to 
> > affect the diagnostic behavior of a caller to that function, since the body 
> > is (typically) irrelevant to the validity of that caller.
> Thanks for the suggestions and clarifications!  The "invalid" bit of decl is 
> subtle, I didn't infer it from the code before, thanks for the explanation.
> 
> Setting the decl invalid seemed much safer to us, and would avoid running a 
> lot of unexpected code paths in clang which might violate the assumptions. 
> 
> > What we should do is add a "contains errors" bit to Stmt, and mark the 
> > function body as containing errors if it has an initializer that contains 
> > an error.
> 
> This sounds promising, but there are no free bit in Stmt at the moment :( (to 
> add the ErrorBit to expr, we have sacrificed the `IsOMPStructuredBlock` bit, 
> it would be easier after the ongoing FPOptions stuff finished, which will 
> free certain bits).
> 
> since this crash is blocking recovery-expr stuff, it is prioritized for us to 
> fix it. Maybe a compromising plan for now is to fix it in 
> `CheckConstexprFunctionDefinition` (just moving the inspecting `InitExpr` 
> code there) -- the crash is from `isPotentialConstantExpr` which is only 
> called in `CheckConstexprFunctionDefinition`, should cover all cases.
I don't think the availability or otherwise of a bit in stmt is the critical 
factor here. Adding a bit to stmt will be a huge amount of work because (unlike 
expr/type) stmts don't have dependence, so there's no existing dependence 
propagation/handling to reuse.

When a ctor has an init expr with an error, I think we ultimately need to 
choose between:
1. ctor is constant-evaluable. (This seems obviously wrong)
2. ctor is not-constant-evaluable. (This creates spurious "must be a constant 
expression" diags)
3. ctor is invalid and therefore we never ask. (This creates other spurious 
diags due to not finding the ctor)
4. ctor-with-errors is handled specially (we find it but don't check it for 
constant-evaluability).

Adding a stmt bit is 4, and is certainly the best long-term direction. 2 seems 
like a reasonable short-term solution though. Can we modify the is-constexpr 
check to return false if errors are present, before asserting there's no 
dependent code?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-04-01 Thread Haojian Wu via Phabricator via cfe-commits
hokein marked 2 inline comments as done.
hokein added inline comments.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:1688
 CheckConstexprKind Kind) {
+  assert(!NewFD->isInvalidDecl());
   const CXXMethodDecl *MD = dyn_cast(NewFD);

rsmith wrote:
> Instead of asserting this, please just return false on an invalid 
> declaration. There's nothing fundamentally wrong with calling this function 
> on an invalid declaration, but as usual, if we encounter something invalid, 
> we should suppress follow-on diagnostics.
oh, thanks. This function is only called in two places, and both of them check 
the NewFD->isValid before calling it, so my understanding is that this function 
is required a valid NewFD.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:5005
+if (Member->getInit() && Member->getInit()->containsErrors())
+  Constructor->setInvalidDecl();
 if (Member->isBaseInitializer())

rsmith wrote:
> rsmith wrote:
> > This is inappropriate. The "invalid" bit on a declaration indicates whether 
> > the declaration is invalid, not whether the definition is invalid.
> > 
> > What we should do is add a "contains errors" bit to `Stmt`, and mark the 
> > function body as containing errors if it has an initializer that contains 
> > an error.
> As an example of why this distinction matters: the "contains errors" bit 
> indicates whether external users of the declaration should ignore it / 
> suppress errors on it, or whether they can still treat it as a regular 
> declaration. It's not ideal for an error in the body of a function to affect 
> the diagnostic behavior of a caller to that function, since the body is 
> (typically) irrelevant to the validity of that caller.
Thanks for the suggestions and clarifications!  The "invalid" bit of decl is 
subtle, I didn't infer it from the code before, thanks for the explanation.

Setting the decl invalid seemed much safer to us, and would avoid running a lot 
of unexpected code paths in clang which might violate the assumptions. 

> What we should do is add a "contains errors" bit to Stmt, and mark the 
> function body as containing errors if it has an initializer that contains an 
> error.

This sounds promising, but there are no free bit in Stmt at the moment :( (to 
add the ErrorBit to expr, we have sacrificed the `IsOMPStructuredBlock` bit, it 
would be easier after the ongoing FPOptions stuff finished, which will free 
certain bits).

since this crash is blocking recovery-expr stuff, it is prioritized for us to 
fix it. Maybe a compromising plan for now is to fix it in 
`CheckConstexprFunctionDefinition` (just moving the inspecting `InitExpr` code 
there) -- the crash is from `isPotentialConstantExpr` which is only called in 
`CheckConstexprFunctionDefinition`, should cover all cases.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-31 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:5005
+if (Member->getInit() && Member->getInit()->containsErrors())
+  Constructor->setInvalidDecl();
 if (Member->isBaseInitializer())

rsmith wrote:
> This is inappropriate. The "invalid" bit on a declaration indicates whether 
> the declaration is invalid, not whether the definition is invalid.
> 
> What we should do is add a "contains errors" bit to `Stmt`, and mark the 
> function body as containing errors if it has an initializer that contains an 
> error.
As an example of why this distinction matters: the "contains errors" bit 
indicates whether external users of the declaration should ignore it / suppress 
errors on it, or whether they can still treat it as a regular declaration. It's 
not ideal for an error in the body of a function to affect the diagnostic 
behavior of a caller to that function, since the body is (typically) irrelevant 
to the validity of that caller.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-31 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith added inline comments.



Comment at: clang/lib/Parse/ParseDeclCXX.cpp:3459-3461
+  if (MemInit.get()->getInit() &&
+  MemInit.get()->getInit()->containsErrors())
+AnyErrors = true;

The parser should not be inspecting properties of `Expr`s -- that's a layering 
violation. Can you move this logic into `ActOnMemInitializers` instead?



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:1688
 CheckConstexprKind Kind) {
+  assert(!NewFD->isInvalidDecl());
   const CXXMethodDecl *MD = dyn_cast(NewFD);

Instead of asserting this, please just return false on an invalid declaration. 
There's nothing fundamentally wrong with calling this function on an invalid 
declaration, but as usual, if we encounter something invalid, we should 
suppress follow-on diagnostics.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:5005
+if (Member->getInit() && Member->getInit()->containsErrors())
+  Constructor->setInvalidDecl();
 if (Member->isBaseInitializer())

This is inappropriate. The "invalid" bit on a declaration indicates whether the 
declaration is invalid, not whether the definition is invalid.

What we should do is add a "contains errors" bit to `Stmt`, and mark the 
function body as containing errors if it has an initializer that contains an 
error.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-31 Thread Haojian Wu via Phabricator via cfe-commits
hokein marked an inline comment as done.
hokein added inline comments.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:5004
 CXXCtorInitializer *Member = Initializers[i];
-
+if (Member->getInit() && Member->getInit()->containsErrors())
+  Constructor->setInvalidDecl();

sammccall wrote:
> what's the case where this gets hit rather than anyerrors=true?
no cases, if `Member->getInit()->containsErrors()` is true, then `anyerrors` is 
always true (this is done in `ParseDeclCXX.cpp`).

the reason why we added the check here is that we mark the constructor as 
invalid only for case `Member->getInit()->containsErrors()` (not for other 
cases leading `anyerrors` to true)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-31 Thread Sam McCall via Phabricator via cfe-commits
sammccall accepted this revision.
sammccall added inline comments.
This revision is now accepted and ready to land.



Comment at: clang/lib/Sema/SemaDeclCXX.cpp:5004
 CXXCtorInitializer *Member = Initializers[i];
-
+if (Member->getInit() && Member->getInit()->containsErrors())
+  Constructor->setInvalidDecl();

what's the case where this gets hit rather than anyerrors=true?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-31 Thread Haojian Wu via Phabricator via cfe-commits
hokein updated this revision to Diff 253809.
hokein marked an inline comment as done.
hokein added a comment.

- mark CtorDecl as invalid when the Initializer init expr contains errors
- add a testcase that would crash the previous version of the patch


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041

Files:
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/invalid-constructor-init.cpp


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {// expected-note 2{{candidate constructor }}
+  int Y;
+  constexpr X() : Y(foo()) {} // expected-error {{use of undeclared identifier 
'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+// FIXME: get rid of the bogus diagnostic below.
+constexpr int Z = X().Y; // expected-error {{no matching constructor for 
initialization of 'X'}}
+
+struct X2 {
+  int Y = foo(); // expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant 
expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a 
constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int) : Y(foo()) {} // expected-error {{use of undeclared 
identifier 'foo'}}
+  // FIXME: get rid of the bogus "delegation cycle" diagnostic
+  // CycleDeclegate(int) is marked as invalid.
+  CycleDelegate(float) : CycleDelegate(1) {} // expected-error {{creates a 
delegation cycle}}
+};
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -1685,6 +1685,7 @@
 // This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
 bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
 CheckConstexprKind Kind) {
+  assert(!NewFD->isInvalidDecl());
   const CXXMethodDecl *MD = dyn_cast(NewFD);
   if (MD && MD->isInstance()) {
 // C++11 [dcl.constexpr]p4:
@@ -5000,7 +5001,8 @@
 
   for (unsigned i = 0; i < Initializers.size(); i++) {
 CXXCtorInitializer *Member = Initializers[i];
-
+if (Member->getInit() && Member->getInit()->containsErrors())
+  Constructor->setInvalidDecl();
 if (Member->isBaseInitializer())
   Info.AllBaseFields[Member->getBaseClass()->getAs()] = Member;
 else {
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -45,6 +45,7 @@
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Support/Casting.h"
 #include 
 #include 
 #include 
Index: clang/lib/Parse/ParseDeclCXX.cpp
===
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -3454,9 +3454,12 @@
 }
 
 MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
-if (!MemInit.isInvalid())
+if (!MemInit.isInvalid()) {
   MemInitializers.push_back(MemInit.get());
-else
+  if (MemInit.get()->getInit() &&
+  MemInit.get()->getInit()->containsErrors())
+AnyErrors = true;
+} else
   AnyErrors = true;
 
 if (Tok.is(tok::comma))


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {// expected-note 2{{candidate constructor }}
+  int Y;
+  constexpr X() : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+};
+// no crash on evaluating the constexpr ctor.
+// FIXME: get rid of the bogus diagnostic below.
+constexpr int Z = X().Y; // expected-error {{no matching constructor for initialization of 'X'}}
+
+struct X2 {
+  int Y = foo(); // expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int) : Y(foo()) {} // expected-error {{use of undeclared identifier 'foo'}}
+  // FIXME: get rid of the bogus "delegation cycle" diagnostic
+  // CycleDeclegate(int) is marked as invalid.
+  CycleDelegate(float) : CycleDelegate(1) {} // expected-error {{creates a delegation cycle}}
+};
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clan

[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-31 Thread Haojian Wu via Phabricator via cfe-commits
hokein added a comment.

> This makes me nervous, marking the constructor as invalid seems much safer. 
> Can you show tests it regresses?

Yeah, the first version of the patch doesn't seem to fix all crashes (X().Y 
would lead another crash)...

so if we mark the CtorDecl as invalid

1. whenever `CtorInitializer->init()->containsError`, we don't have failure 
tests
2. whenever there is any kind of errors (including the containsError case 
above) in CtorInitailizer, we have three failing tests 
(SemaCXX/constant-expression-cxx11.cpp, SemaCXX/constructor-initializer.cpp, 
SemaTemplate/constexpr-instantiate.cpp).

though 1) passes all existing tests, I think it just means current tests don't 
have enough coverage for recoveryExpr cases. But given the current state, 1) 
looks most promising -- fixes the crashes, retains broken expressions in 
CtorInitializer rather than dropping them, doesn't regress the diagnostics a 
lot (only for CtorInitializer->init()->containsError` case).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-30 Thread Sam McCall via Phabricator via cfe-commits
sammccall added a comment.

This makes me nervous, marking the constructor as invalid seems much safer. Can 
you show tests it regresses?




Comment at: clang/lib/Sema/SemaDecl.cpp:14359
+!ErrorsInCtorInitializer &&
 !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose))
   FD->setInvalidDecl();

hokein wrote:
> The crash is in `CheckConstexprFunctionDefinition`, I tried different ways to 
> fixing it:
> 
> 1) mark `FD` invalid when there are any errors in CtorInitailizer -- clang 
> deliberately treats CtorDecl as valid even there are some errors in the 
> initializer to prevent spurious diagnostics (see the cycle delegation in the 
> test as an example), so marking them invalid may affect the quality of 
> diagnostics;
> 
> 2) Fixing it inside `CheckConstexprFunctionDefinition` or 
> `isPotentialConstantExpr`, but it doesn't seem to be a right layer, these 
> functions are expected to be called on a validDecl (or at least after a few 
> sanity checks), and emit diagnostics.
> clang deliberately treats CtorDecl as valid even there are some errors in the 
> initializer
Do you mean currently? (when such errors result in destroying the whole init 
expr)
If so, it would be nice to preserve this indeed.

I'm worried that we're going to decide that a constexpr constructor is valid 
and then actually try to evaluate it at compile time.
What happens if we try to evaluate `constexpr int Z = X().Y` in your testcase?

> Fixing it inside CheckConstexprFunctionDefinition

I have a couple of concerns with where it's currently implemented:
 - aren't there lots of other paths we're going to call isPotentialConstantExpr 
and crash? CheckConstexprFunctionDefinition is large and complicated, 
init-lists are only a small part.
 - if we treat anything with errors in the ctor as valid (am I reading that 
right?!) then won't that mask *other* problems where the non-error parts of the 
definition should cause it to be treated as invalid? e.g. `Foo() : 
m1(broken_but_maybe_constexpr()), m2(exists_and_not_constexpr()) {}`

Wherever this goes, if we're going to do something subtle like marking 
diagnostics as valid based on errors in them, it deserves a comment laying out 
the cases.



Comment at: clang/test/SemaCXX/invalid-constructor-init.cpp:17
+  CycleDelegate(int) : Y(foo()) {} // expected-error {{use of undeclared 
identifier 'foo'}}
+  // no "delegation cycle" diagnostic emitted!
+  CycleDelegate(float) : CycleDelegate(1) {}

what's the behavior with -fno-recovery-ast?
(It'd be nice to improve it, failing to improve it is OK. regressing is 
probably bad...)


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-30 Thread Haojian Wu via Phabricator via cfe-commits
hokein added inline comments.



Comment at: clang/lib/Sema/SemaDecl.cpp:14359
+!ErrorsInCtorInitializer &&
 !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose))
   FD->setInvalidDecl();

The crash is in `CheckConstexprFunctionDefinition`, I tried different ways to 
fixing it:

1) mark `FD` invalid when there are any errors in CtorInitailizer -- clang 
deliberately treats CtorDecl as valid even there are some errors in the 
initializer to prevent spurious diagnostics (see the cycle delegation in the 
test as an example), so marking them invalid may affect the quality of 
diagnostics;

2) Fixing it inside `CheckConstexprFunctionDefinition` or 
`isPotentialConstantExpr`, but it doesn't seem to be a right layer, these 
functions are expected to be called on a validDecl (or at least after a few 
sanity checks), and emit diagnostics.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D77041



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


[PATCH] D77041: [AST] Fix a crash on invalid constexpr Ctorinitializer when building RecoveryExpr.

2020-03-30 Thread Haojian Wu via Phabricator via cfe-commits
hokein created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
hokein edited the summary of this revision.
hokein added inline comments.
hokein added a reviewer: sammccall.



Comment at: clang/lib/Sema/SemaDecl.cpp:14359
+!ErrorsInCtorInitializer &&
 !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose))
   FD->setInvalidDecl();

The crash is in `CheckConstexprFunctionDefinition`, I tried different ways to 
fixing it:

1) mark `FD` invalid when there are any errors in CtorInitailizer -- clang 
deliberately treats CtorDecl as valid even there are some errors in the 
initializer to prevent spurious diagnostics (see the cycle delegation in the 
test as an example), so marking them invalid may affect the quality of 
diagnostics;

2) Fixing it inside `CheckConstexprFunctionDefinition` or 
`isPotentialConstantExpr`, but it doesn't seem to be a right layer, these 
functions are expected to be called on a validDecl (or at least after a few 
sanity checks), and emit diagnostics.


crash stack:

  lang:  workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:13704: bool 
EvaluateInPlace(clang::APValue &, (anonymous namespace)::EvalInfo &, const 
(anonymous namespace)::LValue &, const clang::Expr *, bool): Assertion 
`!E->isValueDependent()' failed.
   #8  EvaluateInPlace(clang::APValue&, (anonymous namespace)::EvalInfo&, 
(anonymous namespace)::LValue const&, clang::Expr const*, bool)  
workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:0:0
   #9  HandleConstructorCall(clang::Expr const*, (anonymous namespace)::LValue 
const&, clang::APValue*, clang::CXXConstructorDecl const*, (anonymous 
namespace)::EvalInfo&, clang::APValue&)  
workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:5779:57
  #10  HandleConstructorCall(clang::Expr const*, (anonymous namespace)::LValue 
const&, llvm::ArrayRef, clang::CXXConstructorDecl const*, 
(anonymous namespace)::EvalInfo&, clang::APValue&)  
workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:5819:10
  #11  clang::Expr::isPotentialConstantExpr(clang::FunctionDecl const*, 
llvm::SmallVectorImpl >&) 
workspace/llvm-project/clang/lib/AST/ExprConstant.cpp:14746:5
  #12  CheckConstexprFunctionBody(clang::Sema&, clang::FunctionDecl const*, 
clang::Stmt*, clang::Sema::CheckConstexprKind)  
workspace/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:2306:7
  #13  clang::Sema::CheckConstexprFunctionDefinition(clang::FunctionDecl 
const*, clang::Sema::CheckConstexprKind)  
workspace/llvm-project/clang/lib/Sema/SemaDeclCXX.cpp:1766:0
  #14  clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool)  
workspace/llvm-project/clang/lib/Sema/SemaDecl.cpp:14357:9
  #15  clang::Parser::ParseFunctionStatementBody(clang::Decl*, 
clang::Parser::ParseScope&)  
workspace/llvm-project/clang/lib/Parse/ParseStmt.cpp:2213:18


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77041

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/invalid-constructor-init.cpp


Index: clang/test/SemaCXX/invalid-constructor-init.cpp
===
--- /dev/null
+++ clang/test/SemaCXX/invalid-constructor-init.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -frecovery-ast -verify %s
+
+struct X {
+  int Y;
+  constexpr X() : Y(foo()) {} // expected-error {{use of undeclared identifier 
'foo'}}
+};
+
+struct X2 {
+  int Y = foo(); // expected-error {{use of undeclared identifier 'foo'}} \
+ // expected-note {{subexpression not valid in a constant 
expression}}
+  constexpr X2() {} // expected-error {{constexpr constructor never produces a 
constant expression}}
+};
+
+struct CycleDelegate {
+  int Y;
+  CycleDelegate(int) : Y(foo()) {} // expected-error {{use of undeclared 
identifier 'foo'}}
+  // no "delegation cycle" diagnostic emitted!
+  CycleDelegate(float) : CycleDelegate(1) {}
+};
Index: clang/lib/Sema/SemaDeclCXX.cpp
===
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -1685,6 +1685,7 @@
 // This implements C++11 [dcl.constexpr]p3,4, as amended by DR1360.
 bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD,
 CheckConstexprKind Kind) {
+  assert(!NewFD->isInvalidDecl());
   const CXXMethodDecl *MD = dyn_cast(NewFD);
   if (MD && MD->isInstance()) {
 // C++11 [dcl.constexpr]p4:
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -45,6 +45,7 @@
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/Triple.h"
+#include "llvm/Support/Casting.h"
 #include 
 #include 
 #include 
@@ -14345,7 +14346,16 @@
   ActivePolicy = &WP;
 }
 
+bool ErrorsInCtorInitializer =
+llvm::isa