[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-11-19 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153701#4656920 , @Endill wrote:

> @yronglin We are sorry it takes so much time to get feedback. Richard and 
> Hubert have little bandwidth for reviews. Others, including me, don't feel 
> qualified to provide good feedback.

@Endill Thanks for your reply, let's wait for them have time. You are clang 
experts, please feel free to comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-11-16 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

ping


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-11-07 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

friendly ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-11-02 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-10-24 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added a comment.

ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-10-14 Thread Yurong via Phabricator via cfe-commits
yronglin marked 2 inline comments as done.
yronglin added a comment.

@rsmith Thanks a lot for your comments and sorry for the very late reply, I was 
on vacation some time ago.

In D153701#4643609 , @rsmith wrote:

> The changes in `SemaInit.cpp` don't look correct to me. Trying to recurse 
> through the initializer and find every nested temporary is highly 
> error-prone; I can't tell you which expression nodes you forgot to recurse 
> through, but I'm sure there are some.
>
> I think the approach being taken here is not really maintainable. We don't 
> want the initialization code to need to know how to recurse through an 
> expression after the fact and find all the temporaries that might need to be 
> lifetime-extended, and we don't need it to do that either. Instead, we should 
> make the expression evaluation context track the current for-range variable, 
> and in `Sema::CreateMaterializeTemporaryExpr`, we should create a temporary 
> that is already set to be lifetime-extended by the loop variable.

I agree, I have reverted the changes in `SemaInit.cpp`. I have ever tried to do 
lifetime-extend in `Sema::CreateMaterializeTemporaryExpr`, but I fall into some 
trouble, the `MaterializeTemporaryExpr` was created before the for-range 
VarDecl, so we don't have a VarDecl for 
`MaterializeTemporaryExpr::setExtendingDecl` in  
`Sema::CreateMaterializeTemporaryExpr`, I have a possible solution here, Eg. we 
allocate a memory block which has same size of VarDecl, and pass this pointer 
to `MaterializeTemporaryExpr::setExtendingDecl` as a placeholder VarDecl, when 
we build the for-range statement, we just construct a VarDecl in the memory 
block that we allocated before. But this approach doesn't look very good and 
not maintainable. So I use `ForRangeInitTemporaryLifetimeExtensionVisitor` to 
visit every temporaries in the initializer and extend the lifetime. And 
`ForRangeInitTemporaryLifetimeExtensionVisitor` was derived from 
`RecursiveASTVisitor`, maybe this approach be able to handle all temporaries. 
WDYT?




Comment at: clang/include/clang/Sema/Sema.h:1356-1357
 
+/// Whether rewrite the default argument.
+bool IsRewriteDefaultArgument = false;
+

rsmith wrote:
> Can you expand this comment to more fully describe what this flag governs? 
> Which default argument? How would it be rewritten?
Yeah, this variable has been removed. By default, all CallExprs in Clang share 
the same CXXDefaultArgExpr from parameters, but in some contexts (such as 
lifetime extension), the lifetime of the temporaries in the current default 
parameters needs to be extended, so the CXXDefaultArgExpr needs to be copied 
and the lifetime of temporaries in the copy need to be extended. 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-10-14 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 557705.
yronglin added a comment.

Update


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-for-range-lifetime.cpp
  clang/test/CXX/special/class.temporary/p6.cpp

Index: clang/test/CXX/special/class.temporary/p6.cpp
===
--- clang/test/CXX/special/class.temporary/p6.cpp
+++ clang/test/CXX/special/class.temporary/p6.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -238,3 +239,236 @@
   // CHECK: call {{.*}}dtor
   // CHECK: }
 }
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK-CXX23: void @_ZN7P2718R05test1Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK-CXX23: void @_ZN7P2718R05test2Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01BD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK-CXX23: void @_ZN7P2718R05test3Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for ([[maybe_unused]] int x : static_cast(LockGuard()), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup11:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end17
+  for ([[maybe_unused]] int x : (void)LockGuard(), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup27:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end33
+  for ([[maybe_unused]] int x : LockGuard(), v)
+LockGuard guard;
+}
+
+// Test default arg
+int (_arg_fn(const A & = A()))[3];
+void test4() {
+
+  // CHECK-CXX23: void @_ZN7P2718R05test4Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn()) 
+bar(e);
+}
+
+struct DefaultA {
+  DefaultA() {}
+  ~DefaultA() {}
+};
+
+A foo(const A&, const DefaultA  = DefaultA()) {
+  return A();
+}
+
+void test5() {
+  // CHECK-CXX23: void @_ZN7P2718R05test5Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn(foo(foo(foo(A())
+bar(e);
+}
+
+struct C : public A {
+  C() {}
+  C(int, const C &, const DefaultA & = DefaultA()) {}
+};
+
+void test6() {
+  // CHECK-CXX23: void @_ZN7P2718R05test6Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23: br label %for.end
+  for (auto e : C(0, C(0, C(0, C()
+bar(e);
+}
+
+// Test member call
+void test7() {
+  // CHECK-CXX23: void @_ZN7P2718R05test7Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-09-11 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-09-06 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 556035.
yronglin added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-for-range-lifetime.cpp
  clang/test/CXX/special/class.temporary/p6.cpp

Index: clang/test/CXX/special/class.temporary/p6.cpp
===
--- clang/test/CXX/special/class.temporary/p6.cpp
+++ clang/test/CXX/special/class.temporary/p6.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -238,3 +239,236 @@
   // CHECK: call {{.*}}dtor
   // CHECK: }
 }
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK-CXX23: void @_ZN7P2718R05test1Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK-CXX23: void @_ZN7P2718R05test2Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01BD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK-CXX23: void @_ZN7P2718R05test3Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for ([[maybe_unused]] int x : static_cast(LockGuard()), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup11:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end17
+  for ([[maybe_unused]] int x : (void)LockGuard(), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup27:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end33
+  for ([[maybe_unused]] int x : LockGuard(), v)
+LockGuard guard;
+}
+
+// Test default arg
+int (_arg_fn(const A & = A()))[3];
+void test4() {
+
+  // CHECK-CXX23: void @_ZN7P2718R05test4Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn()) 
+bar(e);
+}
+
+struct DefaultA {
+  DefaultA() {}
+  ~DefaultA() {}
+};
+
+A foo(const A&, const DefaultA  = DefaultA()) {
+  return A();
+}
+
+void test5() {
+  // CHECK-CXX23: void @_ZN7P2718R05test5Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn(foo(foo(foo(A())
+bar(e);
+}
+
+struct C : public A {
+  C() {}
+  C(int, const C &, const DefaultA & = DefaultA()) {}
+};
+
+void test6() {
+  // CHECK-CXX23: void @_ZN7P2718R05test6Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23: br label %for.end
+  for (auto e : C(0, C(0, C(0, C()
+bar(e);
+}
+
+// Test member call
+void test7() {
+  // CHECK-CXX23: void @_ZN7P2718R05test7Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-09-04 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D158296: [clang] Diagnose overly complex Record in __builtin_dump_struct

2023-09-01 Thread Yurong via Phabricator via cfe-commits
yronglin marked 4 inline comments as done.
yronglin added a comment.

Thank you for your review @aaron.ballman @rsmith , I will be happy to continue 
cook this patch once we reach a consensus.




Comment at: clang/lib/Sema/SemaChecking.cpp:732-733
+int RDKind = RD->isClass() ? 0 : (RD->isStruct() ? 1 : 2);
+S.Diag(PtrArg->getBeginLoc(), diag::err_builtin_dump_struct_too_complex)
+<< RDKind << RD->getName();
+return ExprError();

rsmith wrote:
> aaron.ballman wrote:
> > rsmith wrote:
> > > aaron.ballman wrote:
> > > > This will correctly handle diagnosing a gigantic anonymous struct.
> > > Producing an error here seems likely to eventually cause problems in 
> > > practice for some users: people are using `__builtin_dump_struct` in 
> > > generic code for reflection purposes, not just for debugging, and this 
> > > will cause us to start rejecting complex generic code.
> > > 
> > > Instead of rejecting, can we produce a tree of `PseudoObjectExpr`s if we 
> > > have too many steps to store in a single expression?
> > > Producing an error here seems likely to eventually cause problems in 
> > > practice for some users: people are using __builtin_dump_struct in 
> > > generic code for reflection purposes, not just for debugging, and this 
> > > will cause us to start rejecting complex generic code.
> > >
> > > Instead of rejecting, can we produce a tree of PseudoObjectExprs if we 
> > > have too many steps to store in a single expression?
> > 
> > I think that requires wider discussion -- I don't think 
> > `__builtin_dump_struct` is a reasonable interface we want to support for 
> > reflection (in fact, I'd argue it's an explicit non-goal, the same as 
> > reflection via `-ast-dump`). Compile-time reflection is something we're 
> > likely to need to support more intentionally and I don't think we're going 
> > to want to use this as an interface for it or have to maintain it as a 
> > reflection tool long-term. As such, I think producing a tree of 
> > `PseudoObjectExpr`s is overkill; you can quote me on this a few years from 
> > now when we're laughing at its quaintness, but "16k fields of debug output 
> > is enough for anyone" for a debugging interface.
> > 
> > (That said, I think we should be considering what support we want to add to 
> > the compiler for reflection in service of the work being done in WG21 on 
> > the topic -- if `__builtin_dump_struct` is being used for reflection in 
> > practice, it would be nice to give people a supported, more ergonomic 
> > interface for it that we can use for a future version of C++.)
> The bug report https://github.com/llvm/llvm-project/issues/63169 was 
> encountered by a user hitting the previous 256-element limit in practice when 
> using `__builtin_dump_struct` for reflection. I don't think we can reasonably 
> prevent that from happening, other than -- as you say -- encouraging WG21 to 
> give us a real reflection design we can implement.
fixed.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158296

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


[PATCH] D158296: [clang] Diagnose overly complex Record in __builtin_dump_struct

2023-09-01 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 555376.
yronglin added a comment.

Address Aaron's comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158296

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaChecking.cpp
  clang/test/SemaCXX/builtin-dump-struct.cpp


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -184,3 +184,22 @@
 
 int printf(const char *, ...);
 void f1(t2 w) { __builtin_dump_struct(, printf); }
+
+struct t3 { };
+template
+struct templ {
+T1 v1;
+T1 v2;
+T1 v3;
+T1 v4;
+};
+
+struct t4 {
+  templ> c0;
+  templ> c1;
+  templ> c2;
+};
+
+void aj(...);
+void f2(t4 w) { __builtin_dump_struct(, aj); } // expected-error{{struct 
't4' is too complex to dump}}
+
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -724,6 +724,16 @@
   if (Generator.dumpUnnamedRecord(RD, PtrArg, 0))
 return ExprError();
 
+  // We create a `PseudoObjectExpr` as a wrapper, but the
+  // `PseudoObjectExprBits.NumSubExprs` in `PseudoObjectExpr` restricts its
+  // value to no more than std::numeric_limits::max().
+  if (Generator.Actions.size() > std::numeric_limits::max()) {
+int RDKind = RD->isClass() ? 0 : (RD->isStruct() ? 1 : 2);
+S.Diag(PtrArg->getBeginLoc(), diag::err_builtin_dump_struct_too_complex)
+<< RDKind << RD;
+return ExprError();
+  }
+
   return Generator.buildWrapper();
 }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10176,6 +10176,9 @@
   "argument to __builtin_longjmp must be a constant 1">;
 def err_builtin_requires_language : Error<"'%0' is only available in %1">;
 
+def err_builtin_dump_struct_too_complex : Error<
+"%select{class|struct|union}0 %1 is too complex to dump">;
+
 def err_constant_integer_arg_type : Error<
   "argument to %0 must be a constant integer">;
 


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -184,3 +184,22 @@
 
 int printf(const char *, ...);
 void f1(t2 w) { __builtin_dump_struct(, printf); }
+
+struct t3 { };
+template
+struct templ {
+T1 v1;
+T1 v2;
+T1 v3;
+T1 v4;
+};
+
+struct t4 {
+  templ> c0;
+  templ> c1;
+  templ> c2;
+};
+
+void aj(...);
+void f2(t4 w) { __builtin_dump_struct(, aj); } // expected-error{{struct 't4' is too complex to dump}}
+
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -724,6 +724,16 @@
   if (Generator.dumpUnnamedRecord(RD, PtrArg, 0))
 return ExprError();
 
+  // We create a `PseudoObjectExpr` as a wrapper, but the
+  // `PseudoObjectExprBits.NumSubExprs` in `PseudoObjectExpr` restricts its
+  // value to no more than std::numeric_limits::max().
+  if (Generator.Actions.size() > std::numeric_limits::max()) {
+int RDKind = RD->isClass() ? 0 : (RD->isStruct() ? 1 : 2);
+S.Diag(PtrArg->getBeginLoc(), diag::err_builtin_dump_struct_too_complex)
+<< RDKind << RD;
+return ExprError();
+  }
+
   return Generator.buildWrapper();
 }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10176,6 +10176,9 @@
   "argument to __builtin_longjmp must be a constant 1">;
 def err_builtin_requires_language : Error<"'%0' is only available in %1">;
 
+def err_builtin_dump_struct_too_complex : Error<
+"%select{class|struct|union}0 %1 is too complex to dump">;
+
 def err_constant_integer_arg_type : Error<
   "argument to %0 must be a constant integer">;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-08-30 Thread Yurong via Phabricator via cfe-commits
yronglin marked 2 inline comments as done.
yronglin added inline comments.



Comment at: clang/include/clang/AST/Stmt.h:596-597
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };

dblaikie wrote:
> aaron.ballman wrote:
> > yronglin wrote:
> > > aaron.ballman wrote:
> > > > dblaikie wrote:
> > > > > aaron.ballman wrote:
> > > > > > yronglin wrote:
> > > > > > > yronglin wrote:
> > > > > > > > dblaikie wrote:
> > > > > > > > > yronglin wrote:
> > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > yronglin wrote:
> > > > > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > > > > > > > Could/should we add some error checking in 
> > > > > > > > > > > > > > > > > the ctor to assert that we don't overflow 
> > > > > > > > > > > > > > > > > these longer values/just hit the bug later on?
> > > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > > (& could we use `unsigned short` here rather 
> > > > > > > > > > > > > > > > > than bitfields?)
> > > > > > > > > > > > > > > > We've already got them packed in with other 
> > > > > > > > > > > > > > > > bit-fields from the expression bits, so I think 
> > > > > > > > > > > > > > > > it's reasonable to continue the pattern of 
> > > > > > > > > > > > > > > > using bit-fields (that way we don't 
> > > > > > > > > > > > > > > > accidentally end up with padding between the 
> > > > > > > > > > > > > > > > unnamed bits at the start and the named bits in 
> > > > > > > > > > > > > > > > this object).
> > > > > > > > > > > > > > > > 
> > > > > > > > > > > > > > > > I think adding some assertions would not be a 
> > > > > > > > > > > > > > > > bad idea as a follow-up.
> > > > > > > > > > > > > > > Maybe some unconditional (rather than only in 
> > > > > > > > > > > > > > > asserts builds) error handling? 
> > > > > > > > > > > > > > > (report_fatal_error, if this is low priority 
> > > > > > > > > > > > > > > enough to not have an elegant failure mode, but 
> > > > > > > > > > > > > > > something where we don't just overflow and carry 
> > > > > > > > > > > > > > > on would be good... )
> > > > > > > > > > > > > > Ping on this? I worry this code has just punted the 
> > > > > > > > > > > > > > same bug further down, but not plugged the 
> > > > > > > > > > > > > > hole/ensured we don't overflow on novel/larger 
> > > > > > > > > > > > > > inputs.
> > > > > > > > > > > > > Sorry for the late reply, I was looking through the 
> > > > > > > > > > > > > emails and found this. I agree add some assertions to 
> > > > > > > > > > > > > check the value is a good idea, It's easy to help 
> > > > > > > > > > > > > people catch bugs, at least with when 
> > > > > > > > > > > > > `-DLLVM_ENABLE_ASSERTIONS=ON`, and I'm glad to work 
> > > > > > > > > > > > > on it, but one thing that worries me is that, in 
> > > > > > > > > > > > > ASTReader, we access this field directly, not through 
> > > > > > > > > > > > > the constructor or accessor, and we have to add 
> > > > > > > > > > > > > assertions everywhere. 
> > > > > > > > > > > > > https://github.com/llvm/llvm-project/blob/05b4310c8aec7a050574277ced08a0ab86b27681/clang/lib/Serialization/ASTReaderStmt.cpp#L1382
> > > > > > > > > > > > I don't think we have to add too many assertions. As 
> > > > > > > > > > > > best I can tell, we'll need one in each of the 
> > > > > > > > > > > > `PseudoObjectExpr` constructors and one in 
> > > > > > > > > > > > `ASTStmtReader::VisitPseudoObjectExpr()`, but those are 
> > > > > > > > > > > > the only places we assign a value into the bit-field. 
> > > > > > > > > > > > Three assertions isn't a lot, but if we're worried, we 
> > > > > > > > > > > > could add a setter method that does the assertion and 
> > > > > > > > > > > > use the setter in all three places.
> > > > > > > > > > > My concern wasn't (well, wasn't entirely) about adding 
> > > > > > > > > > > more assertions - but about having a reliable error here. 
> > > > > > > > > > > The patch only makes the sizes larger, but doesn't have a 
> > > > > > > > > > > hard-stop in case those sizes are exceeded again (which, 
> > > > > > > > > > > admittedly, is much harder to do - maybe it's totally 
> > > > > > > > > > > unreachable now, for all practical purposes?) 
> > > > > > > > > > > 
> > > > > > > > > > > I suspect with more carefully constructed recursive 
> > > > > > > > > > > inputs could still reach the higher limit & I think it'd 
> > > > > > > > > > > be good to fail hard in that case in some way? (it's 
> > > > > > > > > > > probably rare enough that a report_fatal_error would 

[PATCH] D158296: [NFC][Clang] Add assertion to check the value of NumSubExprs/ResultIndex does not overflow

2023-08-30 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 554770.
yronglin added a comment.

Addres the comments that we talked in D154784 
.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D158296

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaChecking.cpp
  clang/test/SemaCXX/builtin-dump-struct.cpp


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -184,3 +184,22 @@
 
 int printf(const char *, ...);
 void f1(t2 w) { __builtin_dump_struct(, printf); }
+
+struct t3 { };
+template
+struct templ {
+T1 v1;
+T1 v2;
+T1 v3;
+T1 v4;
+};
+
+struct t4 {
+  templ> c0;
+  templ> c1;
+  templ> c2;
+};
+
+void aj(...);
+void f2(t4 w) { __builtin_dump_struct(, aj); } // expected-error{{struct 
't4' is too complex to dump}}
+
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -724,6 +724,16 @@
   if (Generator.dumpUnnamedRecord(RD, PtrArg, 0))
 return ExprError();
 
+  // We create a `PseudoObjectExpr` as a wrapper, but the
+  // `PseudoObjectExprBits.NumSubExprs` in `PseudoObjectExpr` restricts its
+  // value to no more than std::numeric_limits::max().
+  if (Generator.Actions.size() > std::numeric_limits::max()) {
+int RDKind = RD->isClass() ? 0 : (RD->isStruct() ? 1 : 2);
+S.Diag(PtrArg->getBeginLoc(), diag::err_builtin_dump_struct_too_complex)
+<< RDKind << RD->getName();
+return ExprError();
+  }
+
   return Generator.buildWrapper();
 }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10176,6 +10176,9 @@
   "argument to __builtin_longjmp must be a constant 1">;
 def err_builtin_requires_language : Error<"'%0' is only available in %1">;
 
+def err_builtin_dump_struct_too_complex : Error<
+"%select{class|struct|union}0 '%1' is too complex to dump">;
+
 def err_constant_integer_arg_type : Error<
   "argument to %0 must be a constant integer">;
 


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -184,3 +184,22 @@
 
 int printf(const char *, ...);
 void f1(t2 w) { __builtin_dump_struct(, printf); }
+
+struct t3 { };
+template
+struct templ {
+T1 v1;
+T1 v2;
+T1 v3;
+T1 v4;
+};
+
+struct t4 {
+  templ> c0;
+  templ> c1;
+  templ> c2;
+};
+
+void aj(...);
+void f2(t4 w) { __builtin_dump_struct(, aj); } // expected-error{{struct 't4' is too complex to dump}}
+
Index: clang/lib/Sema/SemaChecking.cpp
===
--- clang/lib/Sema/SemaChecking.cpp
+++ clang/lib/Sema/SemaChecking.cpp
@@ -724,6 +724,16 @@
   if (Generator.dumpUnnamedRecord(RD, PtrArg, 0))
 return ExprError();
 
+  // We create a `PseudoObjectExpr` as a wrapper, but the
+  // `PseudoObjectExprBits.NumSubExprs` in `PseudoObjectExpr` restricts its
+  // value to no more than std::numeric_limits::max().
+  if (Generator.Actions.size() > std::numeric_limits::max()) {
+int RDKind = RD->isClass() ? 0 : (RD->isStruct() ? 1 : 2);
+S.Diag(PtrArg->getBeginLoc(), diag::err_builtin_dump_struct_too_complex)
+<< RDKind << RD->getName();
+return ExprError();
+  }
+
   return Generator.buildWrapper();
 }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10176,6 +10176,9 @@
   "argument to __builtin_longjmp must be a constant 1">;
 def err_builtin_requires_language : Error<"'%0' is only available in %1">;
 
+def err_builtin_dump_struct_too_complex : Error<
+"%select{class|struct|union}0 '%1' is too complex to dump">;
+
 def err_constant_integer_arg_type : Error<
   "argument to %0 must be a constant integer">;
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-29 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

friendly ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-08-24 Thread Yurong via Phabricator via cfe-commits
yronglin marked 2 inline comments as done.
yronglin added inline comments.



Comment at: clang/include/clang/AST/Stmt.h:596-597
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };

aaron.ballman wrote:
> dblaikie wrote:
> > aaron.ballman wrote:
> > > yronglin wrote:
> > > > yronglin wrote:
> > > > > dblaikie wrote:
> > > > > > yronglin wrote:
> > > > > > > dblaikie wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > yronglin wrote:
> > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > > > > Could/should we add some error checking in the ctor 
> > > > > > > > > > > > > > to assert that we don't overflow these longer 
> > > > > > > > > > > > > > values/just hit the bug later on?
> > > > > > > > > > > > > > 
> > > > > > > > > > > > > > (& could we use `unsigned short` here rather than 
> > > > > > > > > > > > > > bitfields?)
> > > > > > > > > > > > > We've already got them packed in with other 
> > > > > > > > > > > > > bit-fields from the expression bits, so I think it's 
> > > > > > > > > > > > > reasonable to continue the pattern of using 
> > > > > > > > > > > > > bit-fields (that way we don't accidentally end up 
> > > > > > > > > > > > > with padding between the unnamed bits at the start 
> > > > > > > > > > > > > and the named bits in this object).
> > > > > > > > > > > > > 
> > > > > > > > > > > > > I think adding some assertions would not be a bad 
> > > > > > > > > > > > > idea as a follow-up.
> > > > > > > > > > > > Maybe some unconditional (rather than only in asserts 
> > > > > > > > > > > > builds) error handling? (report_fatal_error, if this is 
> > > > > > > > > > > > low priority enough to not have an elegant failure 
> > > > > > > > > > > > mode, but something where we don't just overflow and 
> > > > > > > > > > > > carry on would be good... )
> > > > > > > > > > > Ping on this? I worry this code has just punted the same 
> > > > > > > > > > > bug further down, but not plugged the hole/ensured we 
> > > > > > > > > > > don't overflow on novel/larger inputs.
> > > > > > > > > > Sorry for the late reply, I was looking through the emails 
> > > > > > > > > > and found this. I agree add some assertions to check the 
> > > > > > > > > > value is a good idea, It's easy to help people catch bugs, 
> > > > > > > > > > at least with when `-DLLVM_ENABLE_ASSERTIONS=ON`, and I'm 
> > > > > > > > > > glad to work on it, but one thing that worries me is that, 
> > > > > > > > > > in ASTReader, we access this field directly, not through 
> > > > > > > > > > the constructor or accessor, and we have to add assertions 
> > > > > > > > > > everywhere. 
> > > > > > > > > > https://github.com/llvm/llvm-project/blob/05b4310c8aec7a050574277ced08a0ab86b27681/clang/lib/Serialization/ASTReaderStmt.cpp#L1382
> > > > > > > > > I don't think we have to add too many assertions. As best I 
> > > > > > > > > can tell, we'll need one in each of the `PseudoObjectExpr` 
> > > > > > > > > constructors and one in 
> > > > > > > > > `ASTStmtReader::VisitPseudoObjectExpr()`, but those are the 
> > > > > > > > > only places we assign a value into the bit-field. Three 
> > > > > > > > > assertions isn't a lot, but if we're worried, we could add a 
> > > > > > > > > setter method that does the assertion and use the setter in 
> > > > > > > > > all three places.
> > > > > > > > My concern wasn't (well, wasn't entirely) about adding more 
> > > > > > > > assertions - but about having a reliable error here. The patch 
> > > > > > > > only makes the sizes larger, but doesn't have a hard-stop in 
> > > > > > > > case those sizes are exceeded again (which, admittedly, is much 
> > > > > > > > harder to do - maybe it's totally unreachable now, for all 
> > > > > > > > practical purposes?) 
> > > > > > > > 
> > > > > > > > I suspect with more carefully constructed recursive inputs 
> > > > > > > > could still reach the higher limit & I think it'd be good to 
> > > > > > > > fail hard in that case in some way? (it's probably rare enough 
> > > > > > > > that a report_fatal_error would be not-the-worst-thing-ever)
> > > > > > > > 
> > > > > > > > But good assertions would be nice too (the old code only failed 
> > > > > > > > when you hit /exactly/ on just the overflow value, and any more 
> > > > > > > > than that the wraparound would not crash/fail, but misbehave) - 
> > > > > > > > I did add the necessary assertion to ArrayRef (begin <= end) 
> > > > > > > > which would've helped detect this more reliably, but some 
> > > > > > > > assert checking for overflow in the ctor would be good too 
> > > > > > > > (with all the usual nuance/care in 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-24 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

ping~ @hubert.reinterpretcast @rsmith


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-21 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 552009.
yronglin marked 7 inline comments as done.
yronglin added a comment.

Address comments


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-for-range-lifetime.cpp
  clang/test/CXX/special/class.temporary/p6.cpp

Index: clang/test/CXX/special/class.temporary/p6.cpp
===
--- clang/test/CXX/special/class.temporary/p6.cpp
+++ clang/test/CXX/special/class.temporary/p6.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -238,3 +239,236 @@
   // CHECK: call {{.*}}dtor
   // CHECK: }
 }
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK-CXX23: void @_ZN7P2718R05test1Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK-CXX23: void @_ZN7P2718R05test2Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01BD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK-CXX23: void @_ZN7P2718R05test3Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for ([[maybe_unused]] int x : static_cast(LockGuard()), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup11:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end17
+  for ([[maybe_unused]] int x : (void)LockGuard(), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup27:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end33
+  for ([[maybe_unused]] int x : LockGuard(), v)
+LockGuard guard;
+}
+
+// Test default arg
+int (_arg_fn(const A & = A()))[3];
+void test4() {
+
+  // CHECK-CXX23: void @_ZN7P2718R05test4Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn()) 
+bar(e);
+}
+
+struct DefaultA {
+  DefaultA() {}
+  ~DefaultA() {}
+};
+
+A foo(const A&, const DefaultA  = DefaultA()) {
+  return A();
+}
+
+void test5() {
+  // CHECK-CXX23: void @_ZN7P2718R05test5Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn(foo(foo(foo(A())
+bar(e);
+}
+
+struct C : public A {
+  C() {}
+  C(int, const C &, const DefaultA & = DefaultA()) {}
+};
+
+void test6() {
+  // CHECK-CXX23: void @_ZN7P2718R05test6Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23: br label %for.end
+  for (auto e : C(0, C(0, C(0, C()
+bar(e);
+}
+
+// Test member call
+void test7() {
+  // CHECK-CXX23: void @_ZN7P2718R05test7Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-21 Thread Yurong via Phabricator via cfe-commits
yronglin marked 4 inline comments as done.
yronglin added a comment.

@cor3ntin Thanks for your review!




Comment at: clang/include/clang/Sema/Sema.h:1357
+/// Whether rewrite the default argument.
+bool IsRewriteDefaultArgument = false;
+

cor3ntin wrote:
> Can `IsRewriteDefaultArgument` and `MaterializePRValueInDiscardStatement` 
> have different values?
> Maybe `MaterializePRValueInDiscardStatement` is sufficient
Currently they have the same value, but they mean different things, so I use 
two separated variables.



Comment at: clang/include/clang/Sema/Sema.h:1361
+/// Eg. Extending the lifetime of temporaries in the init expression.
+bool IsCheckingCXXForRangeInitVariable = false;
+

cor3ntin wrote:
> Either `IsInLifetimeExtendingContext` or `IsInCXXForRangeInitializer` seem 
> like better names
Thanks for your suggestion, `IsInLifetimeExtendingContext ` looks good to me, I 
can use this var name later.



Comment at: clang/lib/Sema/SemaExpr.cpp:6250
+CallLoc, Param, CurContext};
   EnsureImmediateInvocationInDefaultArgs Immediate(*this);
   ExprResult Res;

@cor3ntin Does `EnsureImmediateInvocationInDefaultArgs` need to be renamed to a 
more generic name?



Comment at: clang/lib/Sema/SemaExpr.cpp:18168
   Prev.InImmediateEscalatingFunctionContext;
-
   Cleanup.reset();

cor3ntin wrote:
> Whitespace only change
Thanks, I'll remove this.



Comment at: clang/lib/Sema/SemaExprCXX.cpp:8206-8209
+// We do not materialize temporay by default in order to avoid creating
+// unnecessary temporary objects. If we skip this step, IR generation is
+// able to synthesize the storage for itself in the aggregate case, and
+// adding the extra node to the AST is just clutter.

cor3ntin wrote:
> Correct me if I'm wrong but the thing we want to avoid here is to avoid 
> creating unnecessary AST nodes, right?
Yeah, ignore unnecessary AST nodes and runtime memory allocation. The redundant 
alloca/store instructions may be removed during the optimization phase.

Eg. 
```
static_cast(42);
```
```
define noundef i32 @main() {
entry:
  %retval = alloca i32, align 4
  %ref.tmp = alloca i32, align 4
  store i32 0, ptr %retval, align 4
  store i32 42, ptr %ref.tmp, align 4
  call void @f()()
  ret i32 0
}
```


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-20 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 551871.
yronglin added a comment.

Do not spass MaterializePRValueInDiscardStatement in 
PushExpressionEvaluationContext.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-for-range-lifetime.cpp
  clang/test/CXX/special/class.temporary/p6.cpp

Index: clang/test/CXX/special/class.temporary/p6.cpp
===
--- clang/test/CXX/special/class.temporary/p6.cpp
+++ clang/test/CXX/special/class.temporary/p6.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -238,3 +239,236 @@
   // CHECK: call {{.*}}dtor
   // CHECK: }
 }
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK-CXX23: void @_ZN7P2718R05test1Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK-CXX23: void @_ZN7P2718R05test2Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01BD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK-CXX23: void @_ZN7P2718R05test3Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for ([[maybe_unused]] int x : static_cast(LockGuard()), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup11:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end17
+  for ([[maybe_unused]] int x : (void)LockGuard(), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup27:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end33
+  for ([[maybe_unused]] int x : LockGuard(), v)
+LockGuard guard;
+}
+
+// Test default arg
+int (_arg_fn(const A & = A()))[3];
+void test4() {
+
+  // CHECK-CXX23: void @_ZN7P2718R05test4Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn()) 
+bar(e);
+}
+
+struct DefaultA {
+  DefaultA() {}
+  ~DefaultA() {}
+};
+
+A foo(const A&, const DefaultA  = DefaultA()) {
+  return A();
+}
+
+void test5() {
+  // CHECK-CXX23: void @_ZN7P2718R05test5Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn(foo(foo(foo(A())
+bar(e);
+}
+
+struct C : public A {
+  C() {}
+  C(int, const C &, const DefaultA & = DefaultA()) {}
+};
+
+void test6() {
+  // CHECK-CXX23: void @_ZN7P2718R05test6Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23: br label %for.end
+  for (auto e : C(0, C(0, C(0, C()
+bar(e);
+}
+
+// Test member call
+void test7() {
+  // CHECK-CXX23: void @_ZN7P2718R05test7Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-20 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 551851.
yronglin added a comment.

Fix ci


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-for-range-lifetime.cpp
  clang/test/CXX/special/class.temporary/p6.cpp

Index: clang/test/CXX/special/class.temporary/p6.cpp
===
--- clang/test/CXX/special/class.temporary/p6.cpp
+++ clang/test/CXX/special/class.temporary/p6.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -238,3 +239,236 @@
   // CHECK: call {{.*}}dtor
   // CHECK: }
 }
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK-CXX23: void @_ZN7P2718R05test1Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK-CXX23: void @_ZN7P2718R05test2Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01BD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK-CXX23: void @_ZN7P2718R05test3Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for ([[maybe_unused]] int x : static_cast(LockGuard()), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup11:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end17
+  for ([[maybe_unused]] int x : (void)LockGuard(), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup27:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end33
+  for ([[maybe_unused]] int x : LockGuard(), v)
+LockGuard guard;
+}
+
+// Test default arg
+int (_arg_fn(const A & = A()))[3];
+void test4() {
+
+  // CHECK-CXX23: void @_ZN7P2718R05test4Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn()) 
+bar(e);
+}
+
+struct DefaultA {
+  DefaultA() {}
+  ~DefaultA() {}
+};
+
+A foo(const A&, const DefaultA  = DefaultA()) {
+  return A();
+}
+
+void test5() {
+  // CHECK-CXX23: void @_ZN7P2718R05test5Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn(foo(foo(foo(A())
+bar(e);
+}
+
+struct C : public A {
+  C() {}
+  C(int, const C &, const DefaultA & = DefaultA()) {}
+};
+
+void test6() {
+  // CHECK-CXX23: void @_ZN7P2718R05test6Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23: br label %for.end
+  for (auto e : C(0, C(0, C(0, C()
+bar(e);
+}
+
+// Test member call
+void test7() {
+  // CHECK-CXX23: void @_ZN7P2718R05test7Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-20 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 551845.
yronglin added a comment.

Fix ci failure, and introduce an variable in ExpressionEvaluationContextRecord 
to rewrite default argument.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/AST/ast-dump-for-range-lifetime.cpp
  clang/test/CXX/special/class.temporary/p6.cpp

Index: clang/test/CXX/special/class.temporary/p6.cpp
===
--- clang/test/CXX/special/class.temporary/p6.cpp
+++ clang/test/CXX/special/class.temporary/p6.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -238,3 +239,236 @@
   // CHECK: call {{.*}}dtor
   // CHECK: }
 }
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK-CXX23: void @_ZN7P2718R05test1Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK-CXX23: void @_ZN7P2718R05test2Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01BD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK-CXX23: void @_ZN7P2718R05test3Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for ([[maybe_unused]] int x : static_cast(LockGuard()), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup11:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end17
+  for ([[maybe_unused]] int x : (void)LockGuard(), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup27:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end33
+  for ([[maybe_unused]] int x : LockGuard(), v)
+LockGuard guard;
+}
+
+// Test default arg
+int (_arg_fn(const A & = A()))[3];
+void test4() {
+
+  // CHECK-CXX23: void @_ZN7P2718R05test4Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn()) 
+bar(e);
+}
+
+struct DefaultA {
+  DefaultA() {}
+  ~DefaultA() {}
+};
+
+A foo(const A&, const DefaultA  = DefaultA()) {
+  return A();
+}
+
+void test5() {
+  // CHECK-CXX23: void @_ZN7P2718R05test5Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn(foo(foo(foo(A())
+bar(e);
+}
+
+struct C : public A {
+  C() {}
+  C(int, const C &, const DefaultA & = DefaultA()) {}
+};
+
+void test6() {
+  // CHECK-CXX23: void @_ZN7P2718R05test6Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23: br label %for.end
+  for (auto e : C(0, C(0, C(0, C()
+bar(e);
+}
+
+// Test member call
+void test7() {
+  // CHECK-CXX23: void @_ZN7P2718R05test7Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void 

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-08-19 Thread Yurong via Phabricator via cfe-commits
yronglin added inline comments.



Comment at: clang/include/clang/AST/Stmt.h:596-597
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };

yronglin wrote:
> dblaikie wrote:
> > yronglin wrote:
> > > dblaikie wrote:
> > > > aaron.ballman wrote:
> > > > > yronglin wrote:
> > > > > > dblaikie wrote:
> > > > > > > dblaikie wrote:
> > > > > > > > aaron.ballman wrote:
> > > > > > > > > dblaikie wrote:
> > > > > > > > > > Could/should we add some error checking in the ctor to 
> > > > > > > > > > assert that we don't overflow these longer values/just hit 
> > > > > > > > > > the bug later on?
> > > > > > > > > > 
> > > > > > > > > > (& could we use `unsigned short` here rather than 
> > > > > > > > > > bitfields?)
> > > > > > > > > We've already got them packed in with other bit-fields from 
> > > > > > > > > the expression bits, so I think it's reasonable to continue 
> > > > > > > > > the pattern of using bit-fields (that way we don't 
> > > > > > > > > accidentally end up with padding between the unnamed bits at 
> > > > > > > > > the start and the named bits in this object).
> > > > > > > > > 
> > > > > > > > > I think adding some assertions would not be a bad idea as a 
> > > > > > > > > follow-up.
> > > > > > > > Maybe some unconditional (rather than only in asserts builds) 
> > > > > > > > error handling? (report_fatal_error, if this is low priority 
> > > > > > > > enough to not have an elegant failure mode, but something where 
> > > > > > > > we don't just overflow and carry on would be good... )
> > > > > > > Ping on this? I worry this code has just punted the same bug 
> > > > > > > further down, but not plugged the hole/ensured we don't overflow 
> > > > > > > on novel/larger inputs.
> > > > > > Sorry for the late reply, I was looking through the emails and 
> > > > > > found this. I agree add some assertions to check the value is a 
> > > > > > good idea, It's easy to help people catch bugs, at least with when 
> > > > > > `-DLLVM_ENABLE_ASSERTIONS=ON`, and I'm glad to work on it, but one 
> > > > > > thing that worries me is that, in ASTReader, we access this field 
> > > > > > directly, not through the constructor or accessor, and we have to 
> > > > > > add assertions everywhere. 
> > > > > > https://github.com/llvm/llvm-project/blob/05b4310c8aec7a050574277ced08a0ab86b27681/clang/lib/Serialization/ASTReaderStmt.cpp#L1382
> > > > > I don't think we have to add too many assertions. As best I can tell, 
> > > > > we'll need one in each of the `PseudoObjectExpr` constructors and one 
> > > > > in `ASTStmtReader::VisitPseudoObjectExpr()`, but those are the only 
> > > > > places we assign a value into the bit-field. Three assertions isn't a 
> > > > > lot, but if we're worried, we could add a setter method that does the 
> > > > > assertion and use the setter in all three places.
> > > > My concern wasn't (well, wasn't entirely) about adding more assertions 
> > > > - but about having a reliable error here. The patch only makes the 
> > > > sizes larger, but doesn't have a hard-stop in case those sizes are 
> > > > exceeded again (which, admittedly, is much harder to do - maybe it's 
> > > > totally unreachable now, for all practical purposes?) 
> > > > 
> > > > I suspect with more carefully constructed recursive inputs could still 
> > > > reach the higher limit & I think it'd be good to fail hard in that case 
> > > > in some way? (it's probably rare enough that a report_fatal_error would 
> > > > be not-the-worst-thing-ever)
> > > > 
> > > > But good assertions would be nice too (the old code only failed when 
> > > > you hit /exactly/ on just the overflow value, and any more than that 
> > > > the wraparound would not crash/fail, but misbehave) - I did add the 
> > > > necessary assertion to ArrayRef (begin <= end) which would've helped 
> > > > detect this more reliably, but some assert checking for overflow in the 
> > > > ctor would be good too (with all the usual nuance/care in checking for 
> > > > overflow) - unless we're going to make that into a fatal or other real 
> > > > error.
> > > Sorry for the very late reply. I have no preference between assertion and 
> > > `llvm_unreachable`, if error then fail fast is looks good. I have a patch 
> > > D158296 to add assertion.
> > Thanks for the assertions - though they still haven't met my main concern 
> > that this should have a hard failure even in a non-assertions build.
> > 
> > I know we don't have a perfect plan/policy for these sort of "run out of 
> > resources/hit a representational limit" issues (at least I don't think we 
> > do... do we, @aaron.ballman ? I know we have some limits (recursion, 
> > template expansion, etc) but they're fairly specific/aren't about every 
> > 

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-08-19 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added inline comments.



Comment at: clang/include/clang/AST/Stmt.h:596-597
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };

dblaikie wrote:
> yronglin wrote:
> > dblaikie wrote:
> > > aaron.ballman wrote:
> > > > yronglin wrote:
> > > > > dblaikie wrote:
> > > > > > dblaikie wrote:
> > > > > > > aaron.ballman wrote:
> > > > > > > > dblaikie wrote:
> > > > > > > > > Could/should we add some error checking in the ctor to assert 
> > > > > > > > > that we don't overflow these longer values/just hit the bug 
> > > > > > > > > later on?
> > > > > > > > > 
> > > > > > > > > (& could we use `unsigned short` here rather than bitfields?)
> > > > > > > > We've already got them packed in with other bit-fields from the 
> > > > > > > > expression bits, so I think it's reasonable to continue the 
> > > > > > > > pattern of using bit-fields (that way we don't accidentally end 
> > > > > > > > up with padding between the unnamed bits at the start and the 
> > > > > > > > named bits in this object).
> > > > > > > > 
> > > > > > > > I think adding some assertions would not be a bad idea as a 
> > > > > > > > follow-up.
> > > > > > > Maybe some unconditional (rather than only in asserts builds) 
> > > > > > > error handling? (report_fatal_error, if this is low priority 
> > > > > > > enough to not have an elegant failure mode, but something where 
> > > > > > > we don't just overflow and carry on would be good... )
> > > > > > Ping on this? I worry this code has just punted the same bug 
> > > > > > further down, but not plugged the hole/ensured we don't overflow on 
> > > > > > novel/larger inputs.
> > > > > Sorry for the late reply, I was looking through the emails and found 
> > > > > this. I agree add some assertions to check the value is a good idea, 
> > > > > It's easy to help people catch bugs, at least with when 
> > > > > `-DLLVM_ENABLE_ASSERTIONS=ON`, and I'm glad to work on it, but one 
> > > > > thing that worries me is that, in ASTReader, we access this field 
> > > > > directly, not through the constructor or accessor, and we have to add 
> > > > > assertions everywhere. 
> > > > > https://github.com/llvm/llvm-project/blob/05b4310c8aec7a050574277ced08a0ab86b27681/clang/lib/Serialization/ASTReaderStmt.cpp#L1382
> > > > I don't think we have to add too many assertions. As best I can tell, 
> > > > we'll need one in each of the `PseudoObjectExpr` constructors and one 
> > > > in `ASTStmtReader::VisitPseudoObjectExpr()`, but those are the only 
> > > > places we assign a value into the bit-field. Three assertions isn't a 
> > > > lot, but if we're worried, we could add a setter method that does the 
> > > > assertion and use the setter in all three places.
> > > My concern wasn't (well, wasn't entirely) about adding more assertions - 
> > > but about having a reliable error here. The patch only makes the sizes 
> > > larger, but doesn't have a hard-stop in case those sizes are exceeded 
> > > again (which, admittedly, is much harder to do - maybe it's totally 
> > > unreachable now, for all practical purposes?) 
> > > 
> > > I suspect with more carefully constructed recursive inputs could still 
> > > reach the higher limit & I think it'd be good to fail hard in that case 
> > > in some way? (it's probably rare enough that a report_fatal_error would 
> > > be not-the-worst-thing-ever)
> > > 
> > > But good assertions would be nice too (the old code only failed when you 
> > > hit /exactly/ on just the overflow value, and any more than that the 
> > > wraparound would not crash/fail, but misbehave) - I did add the necessary 
> > > assertion to ArrayRef (begin <= end) which would've helped detect this 
> > > more reliably, but some assert checking for overflow in the ctor would be 
> > > good too (with all the usual nuance/care in checking for overflow) - 
> > > unless we're going to make that into a fatal or other real error.
> > Sorry for the very late reply. I have no preference between assertion and 
> > `llvm_unreachable`, if error then fail fast is looks good. I have a patch 
> > D158296 to add assertion.
> Thanks for the assertions - though they still haven't met my main concern 
> that this should have a hard failure even in a non-assertions build.
> 
> I know we don't have a perfect plan/policy for these sort of "run out of 
> resources/hit a representational limit" issues (at least I don't think we 
> do... do we, @aaron.ballman ? I know we have some limits (recursion, template 
> expansion, etc) but they're fairly specific/aren't about every possible case 
> of integer overflow in some representational element, etc) but we've seen 
> this one is pretty reachable. 
> 
> Here's a test case 

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-08-18 Thread Yurong via Phabricator via cfe-commits
yronglin marked 3 inline comments as done.
yronglin added inline comments.



Comment at: clang/include/clang/AST/Stmt.h:596-597
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };

dblaikie wrote:
> aaron.ballman wrote:
> > yronglin wrote:
> > > dblaikie wrote:
> > > > dblaikie wrote:
> > > > > aaron.ballman wrote:
> > > > > > dblaikie wrote:
> > > > > > > Could/should we add some error checking in the ctor to assert 
> > > > > > > that we don't overflow these longer values/just hit the bug later 
> > > > > > > on?
> > > > > > > 
> > > > > > > (& could we use `unsigned short` here rather than bitfields?)
> > > > > > We've already got them packed in with other bit-fields from the 
> > > > > > expression bits, so I think it's reasonable to continue the pattern 
> > > > > > of using bit-fields (that way we don't accidentally end up with 
> > > > > > padding between the unnamed bits at the start and the named bits in 
> > > > > > this object).
> > > > > > 
> > > > > > I think adding some assertions would not be a bad idea as a 
> > > > > > follow-up.
> > > > > Maybe some unconditional (rather than only in asserts builds) error 
> > > > > handling? (report_fatal_error, if this is low priority enough to not 
> > > > > have an elegant failure mode, but something where we don't just 
> > > > > overflow and carry on would be good... )
> > > > Ping on this? I worry this code has just punted the same bug further 
> > > > down, but not plugged the hole/ensured we don't overflow on 
> > > > novel/larger inputs.
> > > Sorry for the late reply, I was looking through the emails and found 
> > > this. I agree add some assertions to check the value is a good idea, It's 
> > > easy to help people catch bugs, at least with when 
> > > `-DLLVM_ENABLE_ASSERTIONS=ON`, and I'm glad to work on it, but one thing 
> > > that worries me is that, in ASTReader, we access this field directly, not 
> > > through the constructor or accessor, and we have to add assertions 
> > > everywhere. 
> > > https://github.com/llvm/llvm-project/blob/05b4310c8aec7a050574277ced08a0ab86b27681/clang/lib/Serialization/ASTReaderStmt.cpp#L1382
> > I don't think we have to add too many assertions. As best I can tell, we'll 
> > need one in each of the `PseudoObjectExpr` constructors and one in 
> > `ASTStmtReader::VisitPseudoObjectExpr()`, but those are the only places we 
> > assign a value into the bit-field. Three assertions isn't a lot, but if 
> > we're worried, we could add a setter method that does the assertion and use 
> > the setter in all three places.
> My concern wasn't (well, wasn't entirely) about adding more assertions - but 
> about having a reliable error here. The patch only makes the sizes larger, 
> but doesn't have a hard-stop in case those sizes are exceeded again (which, 
> admittedly, is much harder to do - maybe it's totally unreachable now, for 
> all practical purposes?) 
> 
> I suspect with more carefully constructed recursive inputs could still reach 
> the higher limit & I think it'd be good to fail hard in that case in some 
> way? (it's probably rare enough that a report_fatal_error would be 
> not-the-worst-thing-ever)
> 
> But good assertions would be nice too (the old code only failed when you hit 
> /exactly/ on just the overflow value, and any more than that the wraparound 
> would not crash/fail, but misbehave) - I did add the necessary assertion to 
> ArrayRef (begin <= end) which would've helped detect this more reliably, but 
> some assert checking for overflow in the ctor would be good too (with all the 
> usual nuance/care in checking for overflow) - unless we're going to make that 
> into a fatal or other real error.
Sorry for the very late reply. I have no preference between assertion and 
`llvm_unreachable`, if error then fail fast is looks good. I have a patch 
D158296 to add assertion.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D158296: [Clang] Add assertion to check the value of NumSubExprs/ResultIndex does not overflow

2023-08-18 Thread Yurong via Phabricator via cfe-commits
yronglin created this revision.
Herald added a subscriber: arphaman.
Herald added a project: All.
yronglin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Signed-off-by: yronglin 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D158296

Files:
  clang/include/clang/AST/Expr.h
  clang/lib/AST/Expr.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp


Index: clang/lib/Serialization/ASTReaderStmt.cpp
===
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1378,9 +1378,8 @@
 void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
   VisitExpr(E);
   unsigned numSemanticExprs = Record.readInt();
-  assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
-  E->PseudoObjectExprBits.ResultIndex = Record.readInt();
-
+  assert(numSemanticExprs + 1 == E->getNumSubExprs());
+  E->setResultExprIndex(Record.readInt());
   // Read the syntactic expression.
   E->getSubExprsBuffer()[0] = Record.readSubExpr();
 
Index: clang/lib/AST/Expr.cpp
===
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -4839,7 +4839,7 @@
 
 PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
   : Expr(PseudoObjectExprClass, shell) {
-  PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+  setNumSubExprs(numSemanticExprs + 1);
 }
 
 PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext , Expr *syntax,
@@ -4870,8 +4870,9 @@
Expr *syntax, ArrayRef semantics,
unsigned resultIndex)
 : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary) {
-  PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
-  PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+  
+  setNumSubExprs(semantics.size() + 1);
+  setResultExprIndex(resultIndex + 1);
 
   for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
 Expr *E = (i == 0 ? syntax : semantics[i-1]);
Index: clang/include/clang/AST/Expr.h
===
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -6310,6 +6310,18 @@
 return PseudoObjectExprBits.NumSubExprs;
   }
 
+  void setNumSubExprs(unsigned Val) {
+assert(Val <= std::numeric_limits::max() &&
+   "The value of NumSubExprs too large.");
+PseudoObjectExprBits.NumSubExprs = Val;
+  }
+
+  void setResultExprIndex(unsigned Val) {
+assert(Val <= std::numeric_limits::max() &&
+   "The value of NumSubExprs too large.");
+PseudoObjectExprBits.ResultIndex = Val;
+  }
+
 public:
   /// NoResult - A value for the result index indicating that there is
   /// no semantic result.


Index: clang/lib/Serialization/ASTReaderStmt.cpp
===
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1378,9 +1378,8 @@
 void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
   VisitExpr(E);
   unsigned numSemanticExprs = Record.readInt();
-  assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
-  E->PseudoObjectExprBits.ResultIndex = Record.readInt();
-
+  assert(numSemanticExprs + 1 == E->getNumSubExprs());
+  E->setResultExprIndex(Record.readInt());
   // Read the syntactic expression.
   E->getSubExprsBuffer()[0] = Record.readSubExpr();
 
Index: clang/lib/AST/Expr.cpp
===
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -4839,7 +4839,7 @@
 
 PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
   : Expr(PseudoObjectExprClass, shell) {
-  PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+  setNumSubExprs(numSemanticExprs + 1);
 }
 
 PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext , Expr *syntax,
@@ -4870,8 +4870,9 @@
Expr *syntax, ArrayRef semantics,
unsigned resultIndex)
 : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary) {
-  PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
-  PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+  
+  setNumSubExprs(semantics.size() + 1);
+  setResultExprIndex(resultIndex + 1);
 
   for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
 Expr *E = (i == 0 ? syntax : semantics[i-1]);
Index: clang/include/clang/AST/Expr.h
===
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -6310,6 +6310,18 @@
 return PseudoObjectExprBits.NumSubExprs;
   }
 
+  void setNumSubExprs(unsigned Val) {
+assert(Val <= std::numeric_limits::max() &&
+   "The value of NumSubExprs too large.");
+

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-16 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

friendly ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-14 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153701#4563919 , @yronglin wrote:

> Sorry for the late reply.  I tried to investigate the memory impact of 
> creating these additional materializations by build the whole llvm-project 
> and compare the number of `MaterializedTemporaryExpr` created during parsing.
>
> Steps:
>
> 1. Add a public member `uint64_t NumMetarilizedTemporaryExpr = 0;` in 
> `ASTContext` .
> 2. Increment the value of `NumMetarilizedTemporaryExpr ` in 
> `Sema::CreateMaterializeTemporaryExpr`.
> 3. Write the `NumMetarilizedTemporaryExpr ` into a text file when 
> `ASTContext` destruction, each translation unit will append a line to the 
> file to record the value of `NumMetarilizedTemporaryExpr `.
> 4. Build the entire llvm-project separately using the compiler that creates 
> addational materializations and the compiler that doesn't.
> 5. Sum the numbers produced by each translation unit.
>
> The result is:
>
> | Item | Count |
> | Addational Materialized Temporarys Total | 50655585 |
> | Clang Trunk Total| 18346347 |
> | Diff | 32309238 |
> |
>
> The more detail result in https://yronglin.github.io
>
> The gap between these two numbers is very large. So I'think we can create 
> additional materializations only within for-range initializers. I'm not sure 
> if I can find a way to only create materializes for temporaries that need to 
> have an extended lifetime, WDYT?

I have updated the table, and it was sorted by `Count Inc` col.

**Num files: 7445**

| Item | Count | Mem  |
| Addational Materialized Temporarys Total | 50655585 | 1187240.2734 
(KB)  |
| Clang Trunk Total| 18346347 | 429992.5078 
(KB) |
| Diff | 32309238 | 757247.7656 
(KB) |
| Avg  | 4339.7230 | 4.2380 (KB/file) |


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-14 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

@cor3ntin I have reused `EnsureImmediateInvocationInDefaultArgs` to rewrite 
`CXXDefaultArgExpr`, does this is a correct approach?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-14 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 549896.
yronglin added a comment.

Add test to check generated LLVM IR, and fix crash.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/AST/ast-dump-for-range-lifetime.cpp
  clang/test/CXX/special/class.temporary/p6.cpp

Index: clang/test/CXX/special/class.temporary/p6.cpp
===
--- clang/test/CXX/special/class.temporary/p6.cpp
+++ clang/test/CXX/special/class.temporary/p6.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --implicit-check-not='call{{.*}}dtor'
+// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK-CXX23,CHECK-CXX23-NEXT
 
 namespace std {
   typedef decltype(sizeof(int)) size_t;
@@ -238,3 +239,236 @@
   // CHECK: call {{.*}}dtor
   // CHECK: }
 }
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK-CXX23: void @_ZN7P2718R05test1Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK-CXX23: void @_ZN7P2718R05test2Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01BD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK-CXX23: void @_ZN7P2718R05test3Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for ([[maybe_unused]] int x : static_cast(LockGuard()), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup11:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end17
+  for ([[maybe_unused]] int x : (void)LockGuard(), v)
+LockGuard guard;
+  
+  // CHECK-CXX23: for.cond.cleanup27:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R09LockGuardD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end33
+  for ([[maybe_unused]] int x : LockGuard(), v)
+LockGuard guard;
+}
+
+// Test default arg
+int (_arg_fn(const A & = A()))[3];
+void test4() {
+
+  // CHECK-CXX23: void @_ZN7P2718R05test4Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn()) 
+bar(e);
+}
+
+struct DefaultA {
+  DefaultA() {}
+  ~DefaultA() {}
+};
+
+A foo(const A&, const DefaultA  = DefaultA()) {
+  return A();
+}
+
+void test5() {
+  // CHECK-CXX23: void @_ZN7P2718R05test5Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: br label %for.end
+  for (auto e : default_arg_fn(foo(foo(foo(A())
+bar(e);
+}
+
+struct C : public A {
+  C() {}
+  C(int, const C &, const DefaultA & = DefaultA()) {}
+};
+
+void test6() {
+  // CHECK-CXX23: void @_ZN7P2718R05test6Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R08DefaultAD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01CD1Ev(
+  // CHECK-CXX23: br label %for.end
+  for (auto e : C(0, C(0, C(0, C()
+bar(e);
+}
+
+// Test member call
+void test7() {
+  // CHECK-CXX23: void @_ZN7P2718R05test7Ev()
+  // CHECK-CXX23: for.cond.cleanup:
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void @_ZN7P2718R01AD1Ev(
+  // CHECK-CXX23-NEXT: call void 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-13 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Should we dump the real default argument AST but not only `CXXDefaultArgExpr` 
if `CXXDefaultArgExpr` has been rewritted?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-13 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

FIXME: Need add test in `clang/test/CXX/special/class.temporary/p6.cpp` to 
check generated LLVM IR.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-13 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 549715.
yronglin added a comment.

Handle default argument and dependent context.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/AST/ast-dump-for-range-lifetime.cpp

Index: clang/test/AST/ast-dump-for-range-lifetime.cpp
===
--- /dev/null
+++ clang/test/AST/ast-dump-for-range-lifetime.cpp
@@ -0,0 +1,355 @@
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-linux-gnu -fcxx-exceptions -ast-dump %s \
+// RUN: | FileCheck -strict-whitespace %s
+
+namespace P2718R0 {
+
+// Test basic
+struct A {
+  int a[3] = {1, 2, 3};
+  A() {}
+  ~A() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 3; }
+  A& r() { return *this; }
+  A g() { return A(); }
+};
+
+A g() { return A(); }
+const A (const A ) { return t; }
+
+void test1() {
+  [[maybe_unused]] int sum = 0;
+  // CHECK: FunctionDecl {{.*}} test1 'void ()'
+  // CHECK:  |   `-CXXForRangeStmt {{.*}}
+  // CHECK-NEXT: | |-<<>>
+  // CHECK-NEXT: | |-DeclStmt {{.*}}
+  // CHECK-NEXT: | | `-VarDecl {{.*}} implicit used __range1 'const A &' cinit
+  // CHECK-NEXT: | |   `-ExprWithCleanups {{.*}} 'const A':'const P2718R0::A' lvalue
+  // CHECK-NEXT: | | `-CallExpr {{.*}} 'const A':'const P2718R0::A' lvalue
+  // CHECK-NEXT: | |   |-ImplicitCastExpr {{.*}} 'const A &(*)(const A &)' 
+  // CHECK-NEXT: | |   | `-DeclRefExpr {{.*}} 'const A &(const A &)' lvalue Function {{.*}} 'f1' 'const A &(const A &)'
+  // CHECK-NEXT: | |   `-MaterializeTemporaryExpr {{.*}} 'const A':'const P2718R0::A' lvalue extended by Var {{.*}} '__range1' 'const A &'
+  // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const A':'const P2718R0::A' 
+  // CHECK-NEXT: | |   `-CXXBindTemporaryExpr {{.*}} 'A':'P2718R0::A' (CXXTemporary {{.*}})
+  // CHECK-NEXT: | | `-CallExpr {{.*}} 'A':'P2718R0::A'
+  // CHECK-NEXT: | |   `-ImplicitCastExpr {{.*}} 'A (*)()' 
+  // CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'A ()' lvalue Function {{.*}} 'g' 'A ()'
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct B : A {};
+int ((const A *))[3];
+const A *g(const A &);
+void bar(int) {}
+
+void test2() {
+  // CHECK: FunctionDecl {{.*}} test2 'void ()'
+  // CHECK:  |   `-CXXForRangeStmt {{.*}}
+  // CHECK-NEXT: | |-<<>>
+  // CHECK-NEXT: | |-DeclStmt {{.*}}
+  // CHECK-NEXT: | | `-VarDecl {{.*}} implicit used __range1 'int (&)[3]' cinit
+  // CHECK-NEXT: | |   `-ExprWithCleanups {{.*}} 'int[3]':'int[3]' lvalue
+  // CHECK-NEXT: | | `-CallExpr {{.*}} 'int[3]':'int[3]' lvalue
+  // CHECK-NEXT: | |   |-ImplicitCastExpr {{.*}} 'int (&(*)(const A *))[3]' 
+  // CHECK-NEXT: | |   | `-DeclRefExpr {{.*}} 'int (&(const A *))[3]' lvalue Function {{.*}} 'f' 'int (&(const A *))[3]'
+  // CHECK-NEXT: | |   `-CallExpr {{.*}} 'const A *'
+  // CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'const A *(*)(const A &)' 
+  // CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'const A *(const A &)' lvalue Function {{.*}} 'g' 'const A *(const A &)'
+  // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const A':'const P2718R0::A' lvalue 
+  // CHECK-NEXT: | |   `-MaterializeTemporaryExpr {{.*}} 'const B':'const P2718R0::B' lvalue extended by Var {{.*}} '__range1' 'int (&)[3]'
+  // CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const B':'const P2718R0::B' 
+  // CHECK-NEXT: | |   `-CXXBindTemporaryExpr {{.*}} 'B':'P2718R0::B' (CXXTemporary {{.*}})
+  // CHECK-NEXT: | | `-CXXTemporaryObjectExpr {{.*}} 'B':'P2718R0::B' 'void () noexcept(false)' zeroing
+  for (auto e : f(g(B(
+bar(e);
+}
+
+// Test discard statement.
+struct LockGuard {
+LockGuard() {}
+~LockGuard() {}
+};
+
+void test3() {
+  int v[] = {42, 17, 13};
+
+  // CHECK: FunctionDecl {{.*}} test3 'void ()'
+  // CHECK:  -CXXForRangeStmt {{.*}}
+  // CHECK-NEXT:  |-<<>>
+  // CHECK-NEXT:  |-DeclStmt {{.*}}
+  // CHECK-NEXT:  | `-VarDecl {{.*}} implicit used __range1 'int (&)[3]' cinit
+  // CHECK-NEXT:  |   `-ExprWithCleanups {{.*}} 'int[3]' lvalue
+  // CHECK-NEXT:  | `-BinaryOperator {{.*}} 'int[3]' lvalue ','
+  // CHECK-NEXT:  |   |-CXXStaticCastExpr {{.*}} 'void' static_cast 
+  // CHECK-NEXT:  |   | `-MaterializeTemporaryExpr {{.*}} 'LockGuard':'P2718R0::LockGuard' xvalue extended by Var {{.*}} '__range1' 'int (&)[3]'
+  // CHECK-NEXT:  |   |   `-CXXBindTemporaryExpr {{.*}} 'LockGuard':'P2718R0::LockGuard' (CXXTemporary {{.*}})
+  // 

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-11 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 549449.
yronglin added a comment.

Only create addational metarialized temporary in for-range-init.
FIXME: Need to handle function default argument, and add more test to make sure 
the generated LLVM IR is correct.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-for-range-lifetime.cpp

Index: clang/test/AST/ast-dump-for-range-lifetime.cpp
===
--- /dev/null
+++ clang/test/AST/ast-dump-for-range-lifetime.cpp
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -std=c++23 -triple x86_64-linux-gnu -fcxx-exceptions -ast-dump %s \
+// RUN: | FileCheck -strict-whitespace %s
+
+namespace p2718r0 {
+struct T {
+  int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+  T() {}
+  ~T() {}
+  const int *begin() const { return a; }
+  const int *end() const { return a + 10; }
+};
+
+const T (const T ) { return t; }
+T g() { return T(); }
+
+void foo() {
+  // CHECK: FunctionDecl {{.*}} foo 'void ()'
+  // CHECK: `-CXXForRangeStmt {{.*}}
+  // CHECK-NEXT:|-<<>>
+  // CHECK-NEXT:|-DeclStmt {{.*}}
+  // CHECK-NEXT:| `-VarDecl {{.*}} implicit used __range1 'const T &' cinit
+  // CHECK-NEXT:|   `-ExprWithCleanups {{.*}} 'const T':'const p2718r0::T' lvalue
+  // CHECK-NEXT:| `-CallExpr {{.*}} 'const T':'const p2718r0::T' lvalue
+  // CHECK-NEXT:|   |-ImplicitCastExpr {{.*}} 'const T &(*)(const T &)' 
+  // CHECK-NEXT:|   | `-DeclRefExpr {{.*}} 'const T &(const T &)' lvalue Function {{.*}} 'f1' 'const T &(const T &)'
+  // CHECK-NEXT:|   `-MaterializeTemporaryExpr {{.*}} 'const T':'const p2718r0::T' lvalue extended by Var {{.*}} '__range1' 'const T &'
+  // CHECK-NEXT:| `-ImplicitCastExpr {{.*}} 'const T':'const p2718r0::T' 
+  // CHECK-NEXT:|   `-CXXBindTemporaryExpr {{.*}}  'T':'p2718r0::T' (CXXTemporary {{.*}})
+  // CHECK-NEXT:| `-CallExpr {{.*}} 'T':'p2718r0::T'
+  // CHECK-NEXT:|   `-ImplicitCastExpr {{.*}} 'T (*)()' 
+  // CHECK-NEXT:| `-DeclRefExpr {{.*}} 'T ()' lvalue Function {{.*}} 'g' 'T ()'
+  [[maybe_unused]] int sum = 0;
+  for (auto e : f1(g()))
+sum += e;
+}
+
+struct LockGuard {
+LockGuard(int) {}
+
+~LockGuard() {}
+};
+
+void f() {
+  int v[] = {42, 17, 13};
+  int M = 0;
+
+  // CHECK: FunctionDecl {{.*}} f 'void ()'
+  // CHECK: `-CXXForRangeStmt {{.*}}
+  // CHECK-NEXT:   |-<<>>
+  // CHECK-NEXT:   |-DeclStmt {{.*}}
+  // CHECK-NEXT:   | `-VarDecl {{.*}} col:16 implicit used __range1 'int (&)[3]' cinit
+  // CHECK-NEXT:   |   `-ExprWithCleanups {{.*}} 'int[3]' lvalue
+  // CHECK-NEXT:   | `-BinaryOperator {{.*}} 'int[3]' lvalue ','
+  // CHECK-NEXT:   |   |-CXXStaticCastExpr {{.*}}'void' static_cast 
+  // CHECK-NEXT:   |   | `-MaterializeTemporaryExpr {{.*}} 'LockGuard':'p2718r0::LockGuard' xvalue extended by Var {{.*}} '__range1' 'int (&)[3]'
+  // CHECK-NEXT:   |   |   `-CXXFunctionalCastExpr {{.*}} 'LockGuard':'p2718r0::LockGuard' functional cast to LockGuard 
+  // CHECK-NEXT:   |   | `-CXXBindTemporaryExpr {{.*}} 'LockGuard':'p2718r0::LockGuard' (CXXTemporary {{.*}})
+  // CHECK-NEXT:   |   |   `-CXXConstructExpr {{.*}} 'LockGuard':'p2718r0::LockGuard' 'void (int)'
+  // CHECK-NEXT:   |   | `-ImplicitCastExpr {{.*}} 'int' 
+  // CHECK-NEXT:   |   |   `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'M' 'int'
+  // CHECK-NEXT:   |   `-DeclRefExpr {{.*}} 'int[3]' lvalue Var {{.*}} 'v' 'int[3]'
+  for (int x : static_cast(LockGuard(M)), v) // lock released in C++ 2020
+  {
+LockGuard guard(M); // OK in C++ 2020, now deadlocks
+  }
+}
+
+} // namespace p2718r0
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -27,6 +27,7 @@
 #include "clang/AST/TypeOrdering.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/EnterExpressionEvaluationContext.h"
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/Ownership.h"
@@ -2529,10 +2530,20 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
-  if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
-diag::err_for_range_deduction_failure)) {
-ActOnInitializerError(LoopVar);
-return StmtError();
+  {
+EnterExpressionEvaluationContext RangeVarContext(
+*this, 

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-10 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153701#4575056 , 
@hubert.reinterpretcast wrote:

> In D153701#4563919 , @yronglin 
> wrote:
>
>> The gap between these two numbers is very large. So I'think we can create 
>> additional materializations only within for-range initializers. I'm not sure 
>> if I can find a way to only create materializes for temporaries that need to 
>> have an extended lifetime, WDYT?
>
> @rsmith asked for something slightly different (but I am not sure how to 
> collect that info): He wanted the AST size delta.
>
> For what we have, I think the detailed results table would be more useful if 
> we add some size metric for the files and the increase expressed as a 
> percentage. Perhaps sorting by file size would help contextualize the 
> significance of the percentage change.

Thanks to Aaron's suggestion in Discard, the initial idea was to count the 
number of `MaterializedTemporaryExpr` created in the process of building 
llvm-project, and then calculate the precise memory increment data, without 
being affected by the operating system state. Maybe I can refine this table, 
add a column to show the memory increment  percentage change of each file.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-08-08 Thread Yurong via Phabricator via cfe-commits
yronglin marked 4 inline comments as done.
yronglin added inline comments.



Comment at: clang/include/clang/AST/Stmt.h:596-597
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };

dblaikie wrote:
> dblaikie wrote:
> > aaron.ballman wrote:
> > > dblaikie wrote:
> > > > Could/should we add some error checking in the ctor to assert that we 
> > > > don't overflow these longer values/just hit the bug later on?
> > > > 
> > > > (& could we use `unsigned short` here rather than bitfields?)
> > > We've already got them packed in with other bit-fields from the 
> > > expression bits, so I think it's reasonable to continue the pattern of 
> > > using bit-fields (that way we don't accidentally end up with padding 
> > > between the unnamed bits at the start and the named bits in this object).
> > > 
> > > I think adding some assertions would not be a bad idea as a follow-up.
> > Maybe some unconditional (rather than only in asserts builds) error 
> > handling? (report_fatal_error, if this is low priority enough to not have 
> > an elegant failure mode, but something where we don't just overflow and 
> > carry on would be good... )
> Ping on this? I worry this code has just punted the same bug further down, 
> but not plugged the hole/ensured we don't overflow on novel/larger inputs.
Sorry for the late reply, I was looking through the emails and found this. I 
agree add some assertions to check the value is a good idea, It's easy to help 
people catch bugs, at least with when `-DLLVM_ENABLE_ASSERTIONS=ON`, and I'm 
glad to work on it, but one thing that worries me is that, in ASTReader, we 
access this field directly, not through the constructor or accessor, and we 
have to add assertions everywhere. 
https://github.com/llvm/llvm-project/blob/05b4310c8aec7a050574277ced08a0ab86b27681/clang/lib/Serialization/ASTReaderStmt.cpp#L1382


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D157195: [Clang] Fix the do while statement disappearing in AST when an error occurs in the conditional expression of the do while statement

2023-08-08 Thread Yurong via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
yronglin marked 2 inline comments as done.
Closed by commit rGa2132d72bed1: [Clang] Fix the do while statement 
disappearing in AST when an error occurs in… (authored by yronglin).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157195

Files:
  clang/lib/Parse/ParseStmt.cpp
  clang/test/AST/ast-dump-recovery.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -95,6 +95,8 @@
 TEST_EVALUATE(ForRange, for (auto x : !!){}); // expected-error + {{}}
 TEST_EVALUATE(While, while (!!){});   // expected-error + {{}}
 TEST_EVALUATE(DoWhile, do {} while (!!););// expected-error + {{}}
+TEST_EVALUATE(DoWhileCond, do {} while (some_cond < 10););// 
expected-error {{use of undeclared identifier}}  \
+  // 
expected-error {{constexpr variable 'forceEvaluateDoWhileCond' must be 
initialized by a constant expression}}
 TEST_EVALUATE(If, if (!!){};);// expected-error + {{}}
 TEST_EVALUATE(IfInit, if (auto x = !!; 1){};);// expected-error + {{}}
 TEST_EVALUATE(ForInit, if (!!;;){};); // expected-error + {{}}
Index: clang/test/AST/ast-dump-recovery.cpp
===
--- clang/test/AST/ast-dump-recovery.cpp
+++ clang/test/AST/ast-dump-recovery.cpp
@@ -420,3 +420,15 @@
   // CHECK:  RecoveryExpr {{.*}} '' contains-errors lvalue
   // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
 }
+
+void RecoveryToDoWhileStmtCond() {
+  // CHECK:   FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
+  // CHECK:   `-DoStmt {{.*}}
+  // CHECK-NEXT:|-CompoundStmt {{.*}}
+  // CHECK-NEXT:`-BinaryOperator {{.*}} '' contains-errors 
'<'
+  // CHECK-NEXT:  |-BinaryOperator {{.*}} '' 
contains-errors '+'
+  // CHECK-NEXT:  | |-RecoveryExpr {{.*}} '' 
contains-errors lvalue
+  // CHECK-NEXT:  | `-IntegerLiteral {{.*}} 'int' 1
+  // CHECK-NEXT:  `-IntegerLiteral {{.*}} 'int' 10
+  do {} while (some_invalid_val + 1 < 10);
+}
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1894,7 +1894,8 @@
   ExprResult Cond = ParseExpression();
   // Correct the typos in condition before closing the scope.
   if (Cond.isUsable())
-Cond = Actions.CorrectDelayedTyposInExpr(Cond);
+Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl=*/nullptr,
+ /*RecoverUncorrectedTypos=*/true);
   else {
 if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace))
   SkipUntil(tok::semi);


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -95,6 +95,8 @@
 TEST_EVALUATE(ForRange, for (auto x : !!){}); // expected-error + {{}}
 TEST_EVALUATE(While, while (!!){});   // expected-error + {{}}
 TEST_EVALUATE(DoWhile, do {} while (!!););// expected-error + {{}}
+TEST_EVALUATE(DoWhileCond, do {} while (some_cond < 10););// expected-error {{use of undeclared identifier}}  \
+  // expected-error {{constexpr variable 'forceEvaluateDoWhileCond' must be initialized by a constant expression}}
 TEST_EVALUATE(If, if (!!){};);// expected-error + {{}}
 TEST_EVALUATE(IfInit, if (auto x = !!; 1){};);// expected-error + {{}}
 TEST_EVALUATE(ForInit, if (!!;;){};); // expected-error + {{}}
Index: clang/test/AST/ast-dump-recovery.cpp
===
--- clang/test/AST/ast-dump-recovery.cpp
+++ clang/test/AST/ast-dump-recovery.cpp
@@ -420,3 +420,15 @@
   // CHECK:  RecoveryExpr {{.*}} '' contains-errors lvalue
   // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
 }
+
+void RecoveryToDoWhileStmtCond() {
+  // CHECK:   FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
+  // CHECK:   `-DoStmt {{.*}}
+  // CHECK-NEXT:|-CompoundStmt {{.*}}
+  // CHECK-NEXT:`-BinaryOperator {{.*}} '' contains-errors '<'
+  // CHECK-NEXT:  |-BinaryOperator {{.*}} '' contains-errors '+'
+  // CHECK-NEXT:  | |-RecoveryExpr {{.*}} '' contains-errors lvalue
+  // CHECK-NEXT:  | `-IntegerLiteral {{.*}} 'int' 1
+  // CHECK-NEXT:  `-IntegerLiteral {{.*}} 'int' 10
+  do {} while (some_invalid_val + 1 < 10);
+}
Index: clang/lib/Parse/ParseStmt.cpp

[PATCH] D157195: [Clang] Fix the do while statement disappearing in AST when an error occurs in the conditional expression of the do while statement

2023-08-07 Thread Yurong via Phabricator via cfe-commits
yronglin marked 2 inline comments as done.
yronglin added a comment.

Thanks for your review! @hokein @tbaeder




Comment at: clang/lib/Parse/ParseStmt.cpp:1897-1898
   if (Cond.isUsable())
-Cond = Actions.CorrectDelayedTyposInExpr(Cond);
+Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl*/ nullptr,
+ /*RecoveryUncorrectedTypos*/ 
true);
   else {

tbaeder wrote:
> 
Thanks, done!



Comment at: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp:81
 
+constexpr int test13() { do {} while (a < 10); return 0; }   // expected-error 
{{use of undeclared identifier}}
+static_assert(test13());  // expected-error {{static assertion expression is 
not an integral constant expression}}

hokein wrote:
> nit: it is better to use the below `TEST_EVALUATE` macro for the test, 
> `TEST_EVALUATE(DoWhile2, do {} while (undefined < 10); )`
Thanks, done!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157195

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


[PATCH] D157195: [Clang] Fix the do while statement disappearing in AST when an error occurs in the conditional expression of the do while statement

2023-08-07 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 547712.
yronglin added a comment.

Address comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D157195

Files:
  clang/lib/Parse/ParseStmt.cpp
  clang/test/AST/ast-dump-recovery.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -95,6 +95,8 @@
 TEST_EVALUATE(ForRange, for (auto x : !!){}); // expected-error + {{}}
 TEST_EVALUATE(While, while (!!){});   // expected-error + {{}}
 TEST_EVALUATE(DoWhile, do {} while (!!););// expected-error + {{}}
+TEST_EVALUATE(DoWhileCond, do {} while (some_cond < 10););// 
expected-error {{use of undeclared identifier}}  \
+  // 
expected-error {{constexpr variable 'forceEvaluateDoWhileCond' must be 
initialized by a constant expression}}
 TEST_EVALUATE(If, if (!!){};);// expected-error + {{}}
 TEST_EVALUATE(IfInit, if (auto x = !!; 1){};);// expected-error + {{}}
 TEST_EVALUATE(ForInit, if (!!;;){};); // expected-error + {{}}
Index: clang/test/AST/ast-dump-recovery.cpp
===
--- clang/test/AST/ast-dump-recovery.cpp
+++ clang/test/AST/ast-dump-recovery.cpp
@@ -420,3 +420,15 @@
   // CHECK:  RecoveryExpr {{.*}} '' contains-errors lvalue
   // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
 }
+
+void RecoveryToDoWhileStmtCond() {
+  // CHECK:   FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
+  // CHECK:   `-DoStmt {{.*}}
+  // CHECK-NEXT:|-CompoundStmt {{.*}}
+  // CHECK-NEXT:`-BinaryOperator {{.*}} '' contains-errors 
'<'
+  // CHECK-NEXT:  |-BinaryOperator {{.*}} '' 
contains-errors '+'
+  // CHECK-NEXT:  | |-RecoveryExpr {{.*}} '' 
contains-errors lvalue
+  // CHECK-NEXT:  | `-IntegerLiteral {{.*}} 'int' 1
+  // CHECK-NEXT:  `-IntegerLiteral {{.*}} 'int' 10
+  do {} while (some_invalid_val + 1 < 10);
+}
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1894,7 +1894,8 @@
   ExprResult Cond = ParseExpression();
   // Correct the typos in condition before closing the scope.
   if (Cond.isUsable())
-Cond = Actions.CorrectDelayedTyposInExpr(Cond);
+Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl=*/nullptr,
+ /*RecoverUncorrectedTypos=*/true);
   else {
 if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace))
   SkipUntil(tok::semi);


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -95,6 +95,8 @@
 TEST_EVALUATE(ForRange, for (auto x : !!){}); // expected-error + {{}}
 TEST_EVALUATE(While, while (!!){});   // expected-error + {{}}
 TEST_EVALUATE(DoWhile, do {} while (!!););// expected-error + {{}}
+TEST_EVALUATE(DoWhileCond, do {} while (some_cond < 10););// expected-error {{use of undeclared identifier}}  \
+  // expected-error {{constexpr variable 'forceEvaluateDoWhileCond' must be initialized by a constant expression}}
 TEST_EVALUATE(If, if (!!){};);// expected-error + {{}}
 TEST_EVALUATE(IfInit, if (auto x = !!; 1){};);// expected-error + {{}}
 TEST_EVALUATE(ForInit, if (!!;;){};); // expected-error + {{}}
Index: clang/test/AST/ast-dump-recovery.cpp
===
--- clang/test/AST/ast-dump-recovery.cpp
+++ clang/test/AST/ast-dump-recovery.cpp
@@ -420,3 +420,15 @@
   // CHECK:  RecoveryExpr {{.*}} '' contains-errors lvalue
   // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
 }
+
+void RecoveryToDoWhileStmtCond() {
+  // CHECK:   FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
+  // CHECK:   `-DoStmt {{.*}}
+  // CHECK-NEXT:|-CompoundStmt {{.*}}
+  // CHECK-NEXT:`-BinaryOperator {{.*}} '' contains-errors '<'
+  // CHECK-NEXT:  |-BinaryOperator {{.*}} '' contains-errors '+'
+  // CHECK-NEXT:  | |-RecoveryExpr {{.*}} '' contains-errors lvalue
+  // CHECK-NEXT:  | `-IntegerLiteral {{.*}} 'int' 1
+  // CHECK-NEXT:  `-IntegerLiteral {{.*}} 'int' 10
+  do {} while (some_invalid_val + 1 < 10);
+}
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1894,7 +1894,8 @@
   ExprResult Cond 

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-08-06 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Sorry for the late reply.  I tried to investigate the memory impact of creating 
these additional materializations by build the whole llvm-project and compare 
the number of `MaterializedTemporaryExpr` created during parsing.

Steps:

1. Add a public member `uint64_t NumMetarilizedTemporaryExpr = 0;` in 
`ASTContext` .
2. Increment the value of `NumMetarilizedTemporaryExpr ` in 
`Sema::CreateMaterializeTemporaryExpr`.
3. Write the `NumMetarilizedTemporaryExpr ` into a text file when `ASTContext` 
destruction, each translation unit will append a line to the file to record the 
value of `NumMetarilizedTemporaryExpr `.
4. Build the entire llvm-project separately using the compiler that creates 
addational materializations and the compiler that doesn't.
5. Sum the numbers produced by each translation unit.

The result is:

The version that create addational materializations: 50740658
The version that does not create addational materializations:  18360888

The gap between these two numbers is very large. So I'think we can create 
additional materializations only within for-range initializers. I'm not sure if 
I can find a way to only create materializes for temporaries that need to have 
an extended lifetime, WDYT?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D157195: [Clang] Fix the do while statement disappearing in AST when an error occurs in the conditional expression of the do while statement

2023-08-05 Thread Yurong via Phabricator via cfe-commits
yronglin created this revision.
Herald added a project: All.
yronglin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Signed-off-by: yrong 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157195

Files:
  clang/lib/Parse/ParseStmt.cpp
  clang/test/AST/ast-dump-recovery.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -78,6 +78,9 @@
 constexpr int test12() { return "wrong"; } // expected-error {{cannot 
initialize return object of type 'int'}}
 constexpr int force12 = test12();  // expected-error {{must be 
initialized by a constant}}
 
+constexpr int test13() { do {} while (a < 10); return 0; }   // expected-error 
{{use of undeclared identifier}}
+static_assert(test13());  // expected-error {{static assertion expression is 
not an integral constant expression}}
+
 #define TEST_EVALUATE(Name, X) \
   constexpr int testEvaluate##Name() { \
 X return 0;\
Index: clang/test/AST/ast-dump-recovery.cpp
===
--- clang/test/AST/ast-dump-recovery.cpp
+++ clang/test/AST/ast-dump-recovery.cpp
@@ -420,3 +420,15 @@
   // CHECK:  RecoveryExpr {{.*}} '' contains-errors lvalue
   // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
 }
+
+void RecoveryToDoWhileStmtCond() {
+  // CHECK:   FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
+  // CHECK:   `-DoStmt {{.*}}
+  // CHECK-NEXT:|-CompoundStmt {{.*}}
+  // CHECK-NEXT:`-BinaryOperator {{.*}} '' contains-errors 
'<'
+  // CHECK-NEXT:  |-BinaryOperator {{.*}} '' 
contains-errors '+'
+  // CHECK-NEXT:  | |-RecoveryExpr {{.*}} '' 
contains-errors lvalue
+  // CHECK-NEXT:  | `-IntegerLiteral {{.*}} 'int' 1
+  // CHECK-NEXT:  `-IntegerLiteral {{.*}} 'int' 10
+  do {} while (some_invalid_val + 1 < 10);
+}
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1894,7 +1894,8 @@
   ExprResult Cond = ParseExpression();
   // Correct the typos in condition before closing the scope.
   if (Cond.isUsable())
-Cond = Actions.CorrectDelayedTyposInExpr(Cond);
+Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl*/ nullptr,
+ /*RecoveryUncorrectedTypos*/ 
true);
   else {
 if (!Tok.isOneOf(tok::r_paren, tok::r_square, tok::r_brace))
   SkipUntil(tok::semi);


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -78,6 +78,9 @@
 constexpr int test12() { return "wrong"; } // expected-error {{cannot initialize return object of type 'int'}}
 constexpr int force12 = test12();  // expected-error {{must be initialized by a constant}}
 
+constexpr int test13() { do {} while (a < 10); return 0; }   // expected-error {{use of undeclared identifier}}
+static_assert(test13());  // expected-error {{static assertion expression is not an integral constant expression}}
+
 #define TEST_EVALUATE(Name, X) \
   constexpr int testEvaluate##Name() { \
 X return 0;\
Index: clang/test/AST/ast-dump-recovery.cpp
===
--- clang/test/AST/ast-dump-recovery.cpp
+++ clang/test/AST/ast-dump-recovery.cpp
@@ -420,3 +420,15 @@
   // CHECK:  RecoveryExpr {{.*}} '' contains-errors lvalue
   // CHECK-NEXT: `-DeclRefExpr {{.*}} 'foo' 'int *'
 }
+
+void RecoveryToDoWhileStmtCond() {
+  // CHECK:   FunctionDecl {{.*}} RecoveryToDoWhileStmtCond
+  // CHECK:   `-DoStmt {{.*}}
+  // CHECK-NEXT:|-CompoundStmt {{.*}}
+  // CHECK-NEXT:`-BinaryOperator {{.*}} '' contains-errors '<'
+  // CHECK-NEXT:  |-BinaryOperator {{.*}} '' contains-errors '+'
+  // CHECK-NEXT:  | |-RecoveryExpr {{.*}} '' contains-errors lvalue
+  // CHECK-NEXT:  | `-IntegerLiteral {{.*}} 'int' 1
+  // CHECK-NEXT:  `-IntegerLiteral {{.*}} 'int' 10
+  do {} while (some_invalid_val + 1 < 10);
+}
Index: clang/lib/Parse/ParseStmt.cpp
===
--- clang/lib/Parse/ParseStmt.cpp
+++ clang/lib/Parse/ParseStmt.cpp
@@ -1894,7 +1894,8 @@
   ExprResult Cond = ParseExpression();
   // Correct the typos in condition before closing the scope.
   if (Cond.isUsable())
-Cond = Actions.CorrectDelayedTyposInExpr(Cond);
+Cond = Actions.CorrectDelayedTyposInExpr(Cond, /*InitDecl*/ nullptr,
+  

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-26 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

This is a very early implement, please give me some time to add and fix tests.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-26 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Thanks for your comments and sorry for the very late reply, I have been 
investigating how to achieve it these days.




Comment at: clang/lib/Sema/SemaExprCXX.cpp:8901-8914
+  // [P2718R0] Lifetime extension in range-based for loops.
+  //
+  // 6.7.7 [class.temporary] p5:
+  // There are four contexts in which temporaries are destroyed at a different
+  // point than the end of the full-expression.
+  //
+  // 6.7.7 [class.temporary] p6:

rsmith wrote:
> hubert.reinterpretcast wrote:
> > yronglin wrote:
> > > hubert.reinterpretcast wrote:
> > > > yronglin wrote:
> > > > > hubert.reinterpretcast wrote:
> > > > > > yronglin wrote:
> > > > > > > yronglin wrote:
> > > > > > > > hubert.reinterpretcast wrote:
> > > > > > > > > yronglin wrote:
> > > > > > > > > > rsmith wrote:
> > > > > > > > > > > This isn't the right way to model the behavior here -- 
> > > > > > > > > > > the presence or absence of an `ExprWithCleanups` is just 
> > > > > > > > > > > a convenience to tell consumers of the AST whether they 
> > > > > > > > > > > should expect to see cleanups later or not, and doesn't 
> > > > > > > > > > > carry an implication of affecting the actual temporary 
> > > > > > > > > > > lifetimes and storage durations.
> > > > > > > > > > > 
> > > > > > > > > > > The outcome that we should be aiming to reach is that all 
> > > > > > > > > > > `MaterializeTemporaryExpr`s created as part of processing 
> > > > > > > > > > > the for-range-initializer are marked as being 
> > > > > > > > > > > lifetime-extended by the for-range variable. Probably the 
> > > > > > > > > > > simplest way to handle that would be to track the current 
> > > > > > > > > > > enclosing for-range-initializer variable in the 
> > > > > > > > > > > `ExpressionEvaluationContextRecord`, and whenever a 
> > > > > > > > > > > `MaterializeTemporaryExpr` is created, if there is a 
> > > > > > > > > > > current enclosing for-range-initializer, mark that 
> > > > > > > > > > > `MaterializeTemporaryExpr` as being lifetime-extended by 
> > > > > > > > > > > it.
> > > > > > > > > > Awesome! Thanks a lot for your advice, this is very 
> > > > > > > > > > helpful! I want to take a longer look at it.
> > > > > > > > > As mentioned in D139586, `CXXDefaultArgExpr`s may need 
> > > > > > > > > additional handling. Similarly for `CXXDefaultInitExpr`s.
> > > > > > > > Thanks for your tips! I have a question that what's the correct 
> > > > > > > > way to extent the lifetime of `CXXBindTemporaryExpr`? Can I 
> > > > > > > > just `materialize` the temporary? It may replaced by 
> > > > > > > > `MaterializeTemporaryExpr`, and then I can mark it as being 
> > > > > > > > lifetime-extended by the for-range variable.
> > > > > > > Eg.
> > > > > > > ```
> > > > > > > void f() {
> > > > > > >   int v[] = {42, 17, 13};
> > > > > > >   Mutex m;
> > > > > > >   for (int x : static_cast(LockGuard(m)), v) // lock 
> > > > > > > released in C++ 2020
> > > > > > >   {
> > > > > > > LockGuard guard(m); // OK in C++ 2020, now deadlocks
> > > > > > >   }
> > > > > > > }
> > > > > > > ```
> > > > > > > ```
> > > > > > > BinaryOperator 0x135036220 'int[3]' lvalue ','
> > > > > > > |-CXXStaticCastExpr 0x1350361d0 'void' static_cast 
> > > > > > > | `-CXXFunctionalCastExpr 0x135036198 'LockGuard':'struct 
> > > > > > > LockGuard' functional cast to LockGuard 
> > > > > > > |   `-CXXBindTemporaryExpr 0x135036178 'LockGuard':'struct 
> > > > > > > LockGuard' (CXXTemporary 0x135036178)
> > > > > > > | `-CXXConstructExpr 0x135036140 'LockGuard':'struct 
> > > > > > > LockGuard' 'void (Mutex &)'
> > > > > > > |   `-DeclRefExpr 0x135035e18 'Mutex':'class Mutex' lvalue 
> > > > > > > Var 0x135035b40 'm' 'Mutex':'class Mutex'
> > > > > > > `-DeclRefExpr 0x135036200 'int[3]' lvalue Var 0x135035928 'v' 
> > > > > > > 'int[3]'
> > > > > > > ```
> > > > > > If `MaterializeTemporaryExpr` represents a "temporary 
> > > > > > materialization conversion", then the above should already have one 
> > > > > > just under the `static_cast` to `void` (since the cast operand 
> > > > > > would be a discarded-value expression).
> > > > > > 
> > > > > > There may be unfortunate effects from materializing temporaries for 
> > > > > > discarded-value expressions though: Technically, temporaries are 
> > > > > > also created for objects having scalar type.
> > > > > > 
> > > > > > Currently, `MaterializeTemporaryExpr` is documented as being tied 
> > > > > > to reference binding, but that is not correct: for example, 
> > > > > > `MaterializeTemporaryExpr` also appears when a member access is 
> > > > > > made on a temporary of class type.
> > > > > http://eel.is/c++draft/class.temporary says:
> > > > > ```
> > > > > [Note 3: Temporary objects are materialized:
> > > > > ...
> > > > > (2.6)
> > > > > when a prvalue that has type other than cv void appears as a 
> > > > > discarded-value expression ([expr.context]).
> > > > > — end note]

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-26 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 544386.
yronglin added a comment.

Try implement


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/include/clang/AST/ExprCXX.h
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/Frontend/FrontendActions.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp

Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -410,6 +410,7 @@
   case BuildingBuiltinDumpStructCall:
   case LambdaExpressionSubstitution:
   case BuildingDeductionGuides:
+  case BuiltingCXXForRangeVariable:
 return false;
 
   // This function should never be called when Kind's value is Memoization.
@@ -1009,7 +1010,12 @@
   << convertCallArgsToString(
  *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
   break;
-
+case CodeSynthesisContext::BuiltingCXXForRangeVariable:
+  Diags.Report(Active->PointOfInstantiation,
+   diag::note_building_builtin_dump_struct_call)
+  << convertCallArgsToString(
+ *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs));
+  break;
 case CodeSynthesisContext::Memoization:
   break;
 
@@ -1138,6 +1144,7 @@
 case CodeSynthesisContext::MarkingClassDllexported:
 case CodeSynthesisContext::BuildingBuiltinDumpStructCall:
 case CodeSynthesisContext::BuildingDeductionGuides:
+case CodeSynthesisContext::BuiltingCXXForRangeVariable:
   // This happens in a context unrelated to template instantiation, so
   // there is no SFINAE.
   return std::nullopt;
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2522,6 +2522,12 @@
 }
   }
 
+  // Register a note to explain why we're performing the call.
+  CodeSynthesisContext Ctx;
+  Ctx.Kind = CodeSynthesisContext::BuiltingCXXForRangeVariable;
+  Ctx.PointOfInstantiation = ForLoc;
+  pushCodeSynthesisContext(Ctx);
+
   // Build  auto && __range = range-init
   // Divide by 2, since the variables are in the inner scope (loop body).
   const auto DepthStr = std::to_string(S->getDepth() / 2);
@@ -2529,8 +2535,10 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
-  if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
-diag::err_for_range_deduction_failure)) {
+  bool Res = FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
+   diag::err_for_range_deduction_failure);
+  popCodeSynthesisContext();
+  if (Res) {
 ActOnInitializerError(LoopVar);
 return StmtError();
   }
Index: clang/lib/Sema/SemaInit.cpp
===
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -7355,15 +7355,15 @@
   });
 }
 
-static void visitLocalsRetainedByInitializer(IndirectLocalPath ,
- Expr *Init, LocalVisitor Visit,
- bool RevisitSubinits,
- bool EnableLifetimeWarnings);
+static void
+visitLocalsRetainedByInitializer(IndirectLocalPath , Expr *Init,
+ LocalVisitor Visit, bool RevisitSubinits,
+ bool EnableLifetimeWarnings,
+ bool isCXXForRangeVariable = false);
 
-static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath ,
-  Expr *Init, ReferenceKind RK,
-  LocalVisitor Visit,
-  bool EnableLifetimeWarnings);
+static void visitLocalsRetainedByReferenceBinding(
+IndirectLocalPath , Expr *Init, ReferenceKind RK, LocalVisitor Visit,
+bool EnableLifetimeWarnings, bool isCXXForRangeVariable = false);
 
 template  static bool isRecordWithAttr(QualType Type) {
   if (auto *RD = Type->getAsCXXRecordDecl())
@@ -7543,7 +7543,8 @@
 }
 
 static void visitLifetimeBoundArguments(IndirectLocalPath , Expr *Call,
-LocalVisitor Visit) {
+LocalVisitor Visit,
+bool isCXXForRangeVariable = false) {
   const FunctionDecl *Callee;
   ArrayRef Args;
 
@@ -7584,7 +7585,8 @@
   for (unsigned I = 0,
 N = 

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-13 Thread Yurong via Phabricator via cfe-commits
yronglin marked 2 inline comments as done.
yronglin added inline comments.



Comment at: clang/lib/Sema/SemaExprCXX.cpp:8901-8914
+  // [P2718R0] Lifetime extension in range-based for loops.
+  //
+  // 6.7.7 [class.temporary] p5:
+  // There are four contexts in which temporaries are destroyed at a different
+  // point than the end of the full-expression.
+  //
+  // 6.7.7 [class.temporary] p6:

hubert.reinterpretcast wrote:
> yronglin wrote:
> > hubert.reinterpretcast wrote:
> > > yronglin wrote:
> > > > yronglin wrote:
> > > > > hubert.reinterpretcast wrote:
> > > > > > yronglin wrote:
> > > > > > > rsmith wrote:
> > > > > > > > This isn't the right way to model the behavior here -- the 
> > > > > > > > presence or absence of an `ExprWithCleanups` is just a 
> > > > > > > > convenience to tell consumers of the AST whether they should 
> > > > > > > > expect to see cleanups later or not, and doesn't carry an 
> > > > > > > > implication of affecting the actual temporary lifetimes and 
> > > > > > > > storage durations.
> > > > > > > > 
> > > > > > > > The outcome that we should be aiming to reach is that all 
> > > > > > > > `MaterializeTemporaryExpr`s created as part of processing the 
> > > > > > > > for-range-initializer are marked as being lifetime-extended by 
> > > > > > > > the for-range variable. Probably the simplest way to handle 
> > > > > > > > that would be to track the current enclosing 
> > > > > > > > for-range-initializer variable in the 
> > > > > > > > `ExpressionEvaluationContextRecord`, and whenever a 
> > > > > > > > `MaterializeTemporaryExpr` is created, if there is a current 
> > > > > > > > enclosing for-range-initializer, mark that 
> > > > > > > > `MaterializeTemporaryExpr` as being lifetime-extended by it.
> > > > > > > Awesome! Thanks a lot for your advice, this is very helpful! I 
> > > > > > > want to take a longer look at it.
> > > > > > As mentioned in D139586, `CXXDefaultArgExpr`s may need additional 
> > > > > > handling. Similarly for `CXXDefaultInitExpr`s.
> > > > > Thanks for your tips! I have a question that what's the correct way 
> > > > > to extent the lifetime of `CXXBindTemporaryExpr`? Can I just 
> > > > > `materialize` the temporary? It may replaced by 
> > > > > `MaterializeTemporaryExpr`, and then I can mark it as being 
> > > > > lifetime-extended by the for-range variable.
> > > > Eg.
> > > > ```
> > > > void f() {
> > > >   int v[] = {42, 17, 13};
> > > >   Mutex m;
> > > >   for (int x : static_cast(LockGuard(m)), v) // lock released in 
> > > > C++ 2020
> > > >   {
> > > > LockGuard guard(m); // OK in C++ 2020, now deadlocks
> > > >   }
> > > > }
> > > > ```
> > > > ```
> > > > BinaryOperator 0x135036220 'int[3]' lvalue ','
> > > > |-CXXStaticCastExpr 0x1350361d0 'void' static_cast 
> > > > | `-CXXFunctionalCastExpr 0x135036198 'LockGuard':'struct LockGuard' 
> > > > functional cast to LockGuard 
> > > > |   `-CXXBindTemporaryExpr 0x135036178 'LockGuard':'struct LockGuard' 
> > > > (CXXTemporary 0x135036178)
> > > > | `-CXXConstructExpr 0x135036140 'LockGuard':'struct LockGuard' 
> > > > 'void (Mutex &)'
> > > > |   `-DeclRefExpr 0x135035e18 'Mutex':'class Mutex' lvalue Var 
> > > > 0x135035b40 'm' 'Mutex':'class Mutex'
> > > > `-DeclRefExpr 0x135036200 'int[3]' lvalue Var 0x135035928 'v' 'int[3]'
> > > > ```
> > > If `MaterializeTemporaryExpr` represents a "temporary materialization 
> > > conversion", then the above should already have one just under the 
> > > `static_cast` to `void` (since the cast operand would be a 
> > > discarded-value expression).
> > > 
> > > There may be unfortunate effects from materializing temporaries for 
> > > discarded-value expressions though: Technically, temporaries are also 
> > > created for objects having scalar type.
> > > 
> > > Currently, `MaterializeTemporaryExpr` is documented as being tied to 
> > > reference binding, but that is not correct: for example, 
> > > `MaterializeTemporaryExpr` also appears when a member access is made on a 
> > > temporary of class type.
> > http://eel.is/c++draft/class.temporary says:
> > ```
> > [Note 3: Temporary objects are materialized:
> > ...
> > (2.6)
> > when a prvalue that has type other than cv void appears as a 
> > discarded-value expression ([expr.context]).
> > — end note]
> > ```
> > Seems we should materialized the discard-value expression in this case, 
> > WDYT?
> I think we should, but what is the codegen fallout? Would no-opt builds start 
> writing `42` into allocated memory for `static_cast(42)`?
Thanks for your confirm @hubert.reinterpretcast ! 

I have tried locally, the generated  IR of `void f()` is:
```
define void @f()() {
entry:
  %v = alloca [3 x i32], align 4
  %m = alloca %class.Mutex, align 8
  %__range1 = alloca ptr, align 8
  %ref.tmp = alloca %struct.LockGuard, align 8
  %__begin1 = alloca ptr, align 8
  %__end1 = alloca ptr, align 8
  %x = alloca i32, align 4
  %guard = alloca 

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-13 Thread Yurong via Phabricator via cfe-commits
yronglin added inline comments.



Comment at: clang/lib/Sema/SemaExprCXX.cpp:8901-8914
+  // [P2718R0] Lifetime extension in range-based for loops.
+  //
+  // 6.7.7 [class.temporary] p5:
+  // There are four contexts in which temporaries are destroyed at a different
+  // point than the end of the full-expression.
+  //
+  // 6.7.7 [class.temporary] p6:

hubert.reinterpretcast wrote:
> yronglin wrote:
> > yronglin wrote:
> > > hubert.reinterpretcast wrote:
> > > > yronglin wrote:
> > > > > rsmith wrote:
> > > > > > This isn't the right way to model the behavior here -- the presence 
> > > > > > or absence of an `ExprWithCleanups` is just a convenience to tell 
> > > > > > consumers of the AST whether they should expect to see cleanups 
> > > > > > later or not, and doesn't carry an implication of affecting the 
> > > > > > actual temporary lifetimes and storage durations.
> > > > > > 
> > > > > > The outcome that we should be aiming to reach is that all 
> > > > > > `MaterializeTemporaryExpr`s created as part of processing the 
> > > > > > for-range-initializer are marked as being lifetime-extended by the 
> > > > > > for-range variable. Probably the simplest way to handle that would 
> > > > > > be to track the current enclosing for-range-initializer variable in 
> > > > > > the `ExpressionEvaluationContextRecord`, and whenever a 
> > > > > > `MaterializeTemporaryExpr` is created, if there is a current 
> > > > > > enclosing for-range-initializer, mark that 
> > > > > > `MaterializeTemporaryExpr` as being lifetime-extended by it.
> > > > > Awesome! Thanks a lot for your advice, this is very helpful! I want 
> > > > > to take a longer look at it.
> > > > As mentioned in D139586, `CXXDefaultArgExpr`s may need additional 
> > > > handling. Similarly for `CXXDefaultInitExpr`s.
> > > Thanks for your tips! I have a question that what's the correct way to 
> > > extent the lifetime of `CXXBindTemporaryExpr`? Can I just `materialize` 
> > > the temporary? It may replaced by `MaterializeTemporaryExpr`, and then I 
> > > can mark it as being lifetime-extended by the for-range variable.
> > Eg.
> > ```
> > void f() {
> >   int v[] = {42, 17, 13};
> >   Mutex m;
> >   for (int x : static_cast(LockGuard(m)), v) // lock released in C++ 
> > 2020
> >   {
> > LockGuard guard(m); // OK in C++ 2020, now deadlocks
> >   }
> > }
> > ```
> > ```
> > BinaryOperator 0x135036220 'int[3]' lvalue ','
> > |-CXXStaticCastExpr 0x1350361d0 'void' static_cast 
> > | `-CXXFunctionalCastExpr 0x135036198 'LockGuard':'struct LockGuard' 
> > functional cast to LockGuard 
> > |   `-CXXBindTemporaryExpr 0x135036178 'LockGuard':'struct LockGuard' 
> > (CXXTemporary 0x135036178)
> > | `-CXXConstructExpr 0x135036140 'LockGuard':'struct LockGuard' 'void 
> > (Mutex &)'
> > |   `-DeclRefExpr 0x135035e18 'Mutex':'class Mutex' lvalue Var 
> > 0x135035b40 'm' 'Mutex':'class Mutex'
> > `-DeclRefExpr 0x135036200 'int[3]' lvalue Var 0x135035928 'v' 'int[3]'
> > ```
> If `MaterializeTemporaryExpr` represents a "temporary materialization 
> conversion", then the above should already have one just under the 
> `static_cast` to `void` (since the cast operand would be a discarded-value 
> expression).
> 
> There may be unfortunate effects from materializing temporaries for 
> discarded-value expressions though: Technically, temporaries are also created 
> for objects having scalar type.
> 
> Currently, `MaterializeTemporaryExpr` is documented as being tied to 
> reference binding, but that is not correct: for example, 
> `MaterializeTemporaryExpr` also appears when a member access is made on a 
> temporary of class type.
http://eel.is/c++draft/class.temporary says:
```
[Note 3: Temporary objects are materialized:
...
(2.6)
when a prvalue that has type other than cv void appears as a discarded-value 
expression ([expr.context]).
— end note]
```
Seems we should materialized the discard-value expression in this case, WDYT?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-12 Thread Yurong via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG677a1da6fafd: [clang] Fix crash caused by 
PseudoObjectExprBitfields::NumSubExprs overflow (authored by yronglin).

Changed prior to commit:
  https://reviews.llvm.org/D154784?vs=539563=539798#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Stmt.h
  clang/test/SemaCXX/builtin-dump-struct.cpp


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known 
conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, 
v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -593,10 +593,8 @@
 
 unsigned : NumExprBits;
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };
 
   class SourceLocExprBitfields {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -587,6 +587,8 @@
   (`#50320 `_).
 - Fix an assertion when using ``\u0024`` (``$``) as an identifier, by 
disallowing
   that construct (`#62133 
_`).
+- Fix crash caused by PseudoObjectExprBitfields: NumSubExprs overflow.
+  (`#63169 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-12 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Wait for CI green


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-12 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 539563.
yronglin added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Stmt.h
  clang/test/SemaCXX/builtin-dump-struct.cpp


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known 
conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, 
v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -593,10 +593,8 @@
 
 unsigned : NumExprBits;
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };
 
   class SourceLocExprBitfields {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -591,6 +591,8 @@
   (`#38717 _`).
 - Fix an assertion when using ``\u0024`` (``$``) as an identifier, by 
disallowing
   that construct (`#62133 
_`).
+- Fix crash caused by PseudoObjectExprBitfields: NumSubExprs overflow.
+  (`#63169 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/include/clang/AST/Stmt.h

[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-12 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added inline comments.



Comment at: clang/lib/Sema/SemaExprCXX.cpp:8901-8914
+  // [P2718R0] Lifetime extension in range-based for loops.
+  //
+  // 6.7.7 [class.temporary] p5:
+  // There are four contexts in which temporaries are destroyed at a different
+  // point than the end of the full-expression.
+  //
+  // 6.7.7 [class.temporary] p6:

yronglin wrote:
> hubert.reinterpretcast wrote:
> > yronglin wrote:
> > > rsmith wrote:
> > > > This isn't the right way to model the behavior here -- the presence or 
> > > > absence of an `ExprWithCleanups` is just a convenience to tell 
> > > > consumers of the AST whether they should expect to see cleanups later 
> > > > or not, and doesn't carry an implication of affecting the actual 
> > > > temporary lifetimes and storage durations.
> > > > 
> > > > The outcome that we should be aiming to reach is that all 
> > > > `MaterializeTemporaryExpr`s created as part of processing the 
> > > > for-range-initializer are marked as being lifetime-extended by the 
> > > > for-range variable. Probably the simplest way to handle that would be 
> > > > to track the current enclosing for-range-initializer variable in the 
> > > > `ExpressionEvaluationContextRecord`, and whenever a 
> > > > `MaterializeTemporaryExpr` is created, if there is a current enclosing 
> > > > for-range-initializer, mark that `MaterializeTemporaryExpr` as being 
> > > > lifetime-extended by it.
> > > Awesome! Thanks a lot for your advice, this is very helpful! I want to 
> > > take a longer look at it.
> > As mentioned in D139586, `CXXDefaultArgExpr`s may need additional handling. 
> > Similarly for `CXXDefaultInitExpr`s.
> Thanks for your tips! I have a question that what's the correct way to extent 
> the lifetime of `CXXBindTemporaryExpr`? Can I just `materialize` the 
> temporary? It may replaced by `MaterializeTemporaryExpr`, and then I can mark 
> it as being lifetime-extended by the for-range variable.
Eg.
```
void f() {
  int v[] = {42, 17, 13};
  Mutex m;
  for (int x : static_cast(LockGuard(m)), v) // lock released in C++ 2020
  {
LockGuard guard(m); // OK in C++ 2020, now deadlocks
  }
}
```
```
BinaryOperator 0x135036220 'int[3]' lvalue ','
|-CXXStaticCastExpr 0x1350361d0 'void' static_cast 
| `-CXXFunctionalCastExpr 0x135036198 'LockGuard':'struct LockGuard' functional 
cast to LockGuard 
|   `-CXXBindTemporaryExpr 0x135036178 'LockGuard':'struct LockGuard' 
(CXXTemporary 0x135036178)
| `-CXXConstructExpr 0x135036140 'LockGuard':'struct LockGuard' 'void 
(Mutex &)'
|   `-DeclRefExpr 0x135035e18 'Mutex':'class Mutex' lvalue Var 0x135035b40 
'm' 'Mutex':'class Mutex'
`-DeclRefExpr 0x135036200 'int[3]' lvalue Var 0x135035928 'v' 'int[3]'
```


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [WIP][Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-12 Thread Yurong via Phabricator via cfe-commits
yronglin marked 2 inline comments as done.
yronglin added inline comments.



Comment at: clang/lib/Sema/SemaExprCXX.cpp:8901-8914
+  // [P2718R0] Lifetime extension in range-based for loops.
+  //
+  // 6.7.7 [class.temporary] p5:
+  // There are four contexts in which temporaries are destroyed at a different
+  // point than the end of the full-expression.
+  //
+  // 6.7.7 [class.temporary] p6:

hubert.reinterpretcast wrote:
> yronglin wrote:
> > rsmith wrote:
> > > This isn't the right way to model the behavior here -- the presence or 
> > > absence of an `ExprWithCleanups` is just a convenience to tell consumers 
> > > of the AST whether they should expect to see cleanups later or not, and 
> > > doesn't carry an implication of affecting the actual temporary lifetimes 
> > > and storage durations.
> > > 
> > > The outcome that we should be aiming to reach is that all 
> > > `MaterializeTemporaryExpr`s created as part of processing the 
> > > for-range-initializer are marked as being lifetime-extended by the 
> > > for-range variable. Probably the simplest way to handle that would be to 
> > > track the current enclosing for-range-initializer variable in the 
> > > `ExpressionEvaluationContextRecord`, and whenever a 
> > > `MaterializeTemporaryExpr` is created, if there is a current enclosing 
> > > for-range-initializer, mark that `MaterializeTemporaryExpr` as being 
> > > lifetime-extended by it.
> > Awesome! Thanks a lot for your advice, this is very helpful! I want to take 
> > a longer look at it.
> As mentioned in D139586, `CXXDefaultArgExpr`s may need additional handling. 
> Similarly for `CXXDefaultInitExpr`s.
Thanks for your tips! I have a question that what's the correct way to extent 
the lifetime of `CXXBindTemporaryExpr`? Can I just `materialize` the temporary? 
It may replaced by `MaterializeTemporaryExpr`, and then I can mark it as being 
lifetime-extended by the for-range variable.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-12 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added a comment.

Thanks for your review! @aaron.ballman @rjmccall


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-12 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added inline comments.



Comment at: clang/include/clang/AST/Stmt.h:603
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+// Whether the PseudoObjectExpr has result.
+unsigned HasResult : 1;

rjmccall wrote:
> aaron.ballman wrote:
> > 
> Please remove the comment, which is incorrect.  Otherwise, I think this is 
> fine.
Thanks, removed.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-12 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 539493.
yronglin added a comment.

Address comment


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Stmt.h
  clang/test/SemaCXX/builtin-dump-struct.cpp


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known 
conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, 
v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -593,10 +593,8 @@
 
 unsigned : NumExprBits;
 
-// These don't need to be particularly wide, because they're
-// strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };
 
   class SourceLocExprBitfields {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -591,6 +591,8 @@
   (`#38717 _`).
 - Fix an assertion when using ``\u0024`` (``$``) as an identifier, by 
disallowing
   that construct (`#62133 
_`).
+- Fix crash caused by PseudoObjectExprBitfields: NumSubExprs overflow.
+  (`#63169 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/include/clang/AST/Stmt.h

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-11 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 539152.
yronglin added a comment.

Address John's comment.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Stmt.h
  clang/test/SemaCXX/builtin-dump-struct.cpp


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known 
conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, 
v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, 
v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, 
v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, 
v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, 
v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, 
v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -595,8 +595,8 @@
 
 // These don't need to be particularly wide, because they're
 // strictly limited by the forms of expressions we permit.
-unsigned NumSubExprs : 8;
-unsigned ResultIndex : 32 - 8 - NumExprBits;
+unsigned NumSubExprs : 16;
+unsigned ResultIndex : 16;
   };
 
   class SourceLocExprBitfields {
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -582,6 +582,8 @@
   (`#50243 `_),
   (`#48636 `_),
   (`#50320 `_).
+- Fix crash caused by PseudoObjectExprBitfields: NumSubExprs overflow.
+  (`#63169 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/include/clang/AST/Stmt.h
===
--- 

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-11 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D154784#4486721 , @rjmccall wrote:

> We had that discussion in the bug report.  Let's just increase the widths 
> unconditionally; this is not such a common expression class that we need to 
> worry about using an extra word.

Thanks for your review!

> Let's just increase the widths unconditionally

Do you mean:

  class PseudoObjectExprBitfields {
  friend class ASTStmtReader; // deserialization
  friend class PseudoObjectExpr;
  
  unsigned : NumExprBits;
  unsigned NumSubExprs : 16;
  unsigned ResultIndex : 16;
};


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-10 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D154784#4485752 , @aaron.ballman 
wrote:

> In general, I think this is a good approach. However, it sort of kicks the 
> can down the road a bit; we will still overflow the member if there are 
> enough fields. Would it make sense to also add a diagnostic to Sema so that 
> overflow with the widened fields is diagnosed rather than causing a crash?

Thanks you for take a look!

> Would it make sense to also add a diagnostic to Sema so that overflow with 
> the widened fields is diagnosed rather than causing a crash?

Ah, I think your are right. It doesn't make sense, As the comments for 
`PseudoObjectExprBitfields` says `These don't need to be particularly wide, 
because they're strictly limited by the forms of expressions we permit.` I 
think developers who use `PseudoObjectExprBitfields` need to be more careful.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-10 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 538712.
yronglin marked 2 inline comments as done.
yronglin added a comment.

Update comments in PseudoObjectExpr.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/Stmt.h
  clang/lib/AST/Expr.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/test/SemaCXX/builtin-dump-struct.cpp

Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1378,8 +1378,15 @@
 void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
   VisitExpr(E);
   unsigned numSemanticExprs = Record.readInt();
-  assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
-  E->PseudoObjectExprBits.ResultIndex = Record.readInt();
+  assert(numSemanticExprs + 1 == E->getNumSubExprs());
+
+  unsigned ResultIndex = Record.readInt();
+  if (ResultIndex) {
+E->PseudoObjectExprBits.HasResult = true;
+E->PseudoObjectExprBits.ResultBits.ResultIndex = ResultIndex;
+  } else {
+E->PseudoObjectExprBits.HasResult = false;
+  }
 
   // Read the syntactic expression.
   E->getSubExprsBuffer()[0] = Record.readSubExpr();
Index: clang/lib/AST/Expr.cpp
===
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -4842,7 +4842,8 @@
 
 PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
   : Expr(PseudoObjectExprClass, shell) {
-  PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+  PseudoObjectExprBits.HasResult = false;
+  PseudoObjectExprBits.NumSubExprsIfNoResult = numSemanticExprs + 1;
 }
 
 PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext , Expr *syntax,
@@ -4873,8 +4874,15 @@
Expr *syntax, ArrayRef semantics,
unsigned resultIndex)
 : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary) {
-  PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
-  PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+
+  if (resultIndex == NoResult) {
+PseudoObjectExprBits.HasResult = false;
+PseudoObjectExprBits.NumSubExprsIfNoResult = semantics.size() + 1;
+  } else {
+PseudoObjectExprBits.HasResult = true;
+PseudoObjectExprBits.ResultBits.NumSubExprs = semantics.size() + 1;
+PseudoObjectExprBits.ResultBits.ResultIndex = resultIndex + 1;
+  }
 
   for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
 Expr *E = (i == 0 ? syntax : semantics[i-1]);
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -591,12 +591,26 @@
 friend class ASTStmtReader; // deserialization
 friend class PseudoObjectExpr;
 
+struct ResultBitfields {
+  // These don't need to be particularly wide, because they're
+  // strictly limited by the forms of expressions we permit.
+  unsigned NumSubExprs : 16;
+  unsigned ResultIndex : 16;
+};
+
 unsigned 

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-10 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 538709.
yronglin added a comment.

Address Aaron's comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/Stmt.h
  clang/lib/AST/Expr.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/test/SemaCXX/builtin-dump-struct.cpp

Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,28 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow. This
+// would previously cause a crash.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1378,8 +1378,15 @@
 void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
   VisitExpr(E);
   unsigned numSemanticExprs = Record.readInt();
-  assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
-  E->PseudoObjectExprBits.ResultIndex = Record.readInt();
+  assert(numSemanticExprs + 1 == E->getNumSubExprs());
+
+  unsigned ResultIndex = Record.readInt();
+  if (ResultIndex) {
+E->PseudoObjectExprBits.HasResult = true;
+E->PseudoObjectExprBits.ResultBits.ResultIndex = ResultIndex;
+  } else {
+E->PseudoObjectExprBits.HasResult = false;
+  }
 
   // Read the syntactic expression.
   E->getSubExprsBuffer()[0] = Record.readSubExpr();
Index: clang/lib/AST/Expr.cpp
===
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -4842,7 +4842,8 @@
 
 PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
   : Expr(PseudoObjectExprClass, shell) {
-  PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+  PseudoObjectExprBits.HasResult = false;
+  PseudoObjectExprBits.NumSubExprsIfNoResult = numSemanticExprs + 1;
 }
 
 PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext , Expr *syntax,
@@ -4873,8 +4874,15 @@
Expr *syntax, ArrayRef semantics,
unsigned resultIndex)
 : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary) {
-  PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
-  PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+
+  if (resultIndex == NoResult) {
+PseudoObjectExprBits.HasResult = false;
+PseudoObjectExprBits.NumSubExprsIfNoResult = semantics.size() + 1;
+  } else {
+PseudoObjectExprBits.HasResult = true;
+PseudoObjectExprBits.ResultBits.NumSubExprs = semantics.size() + 1;
+PseudoObjectExprBits.ResultBits.ResultIndex = resultIndex + 1;
+  }
 
   for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
 Expr *E = (i == 0 ? syntax : semantics[i-1]);
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -591,12 +591,26 @@
 friend class ASTStmtReader; // deserialization
 friend class PseudoObjectExpr;
 
+struct ResultBitfields {
+  // These don't need to be particularly wide, because they're
+  // strictly limited by the forms of expressions we permit.
+  unsigned NumSubExprs : 16;
+  unsigned ResultIndex : 16;
+};
+
 unsigned : NumExprBits;
 
-// These don't need to be 

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-09 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

I'm not sure if we should limit the value of `NumSubExprs` when build  
`PseudoObjectExpr` for `__builtin_dump_struct`, This cost too much memory when 
the nested members of the record are very deep and the num of member is very 
large.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

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


[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-09 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 538418.
yronglin added a comment.

Format


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/Stmt.h
  clang/lib/AST/Expr.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/test/SemaCXX/builtin-dump-struct.cpp

Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,27 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1378,8 +1378,15 @@
 void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
   VisitExpr(E);
   unsigned numSemanticExprs = Record.readInt();
-  assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
-  E->PseudoObjectExprBits.ResultIndex = Record.readInt();
+  assert(numSemanticExprs + 1 == E->getNumSubExprs());
+
+  unsigned ResultIndex = Record.readInt();
+  if (ResultIndex) {
+E->PseudoObjectExprBits.HasResult = true;
+E->PseudoObjectExprBits.ResultBits.ResultIndex = ResultIndex;
+  } else {
+E->PseudoObjectExprBits.HasResult = false;
+  }
 
   // Read the syntactic expression.
   E->getSubExprsBuffer()[0] = Record.readSubExpr();
Index: clang/lib/AST/Expr.cpp
===
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -4848,7 +4848,8 @@
 
 PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
   : Expr(PseudoObjectExprClass, shell) {
-  PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+  PseudoObjectExprBits.HasResult = false;
+  PseudoObjectExprBits.NumSubExprsIfNoResult = numSemanticExprs + 1;
 }
 
 PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext , Expr *syntax,
@@ -4879,8 +4880,15 @@
Expr *syntax, ArrayRef semantics,
unsigned resultIndex)
 : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary) {
-  PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
-  PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+
+  if (resultIndex == NoResult) {
+PseudoObjectExprBits.HasResult = false;
+PseudoObjectExprBits.NumSubExprsIfNoResult = semantics.size() + 1;
+  } else {
+PseudoObjectExprBits.HasResult = true;
+PseudoObjectExprBits.ResultBits.NumSubExprs = semantics.size() + 1;
+PseudoObjectExprBits.ResultBits.ResultIndex = resultIndex + 1;
+  }
 
   for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
 Expr *E = (i == 0 ? syntax : semantics[i-1]);
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -591,12 +591,26 @@
 friend class ASTStmtReader; // deserialization
 friend class PseudoObjectExpr;
 
+struct ResultBitfields {
+  // These don't need to be particularly wide, because they're
+  // strictly limited by the forms of expressions we permit.
+  unsigned NumSubExprs : 16;
+  unsigned ResultIndex : 16;
+};
+
 unsigned : NumExprBits;
 
-// These don't need to be particularly wide, because they're
-// strictly limited by 

[PATCH] D154784: [clang] Fix crash caused by PseudoObjectExprBitfields::NumSubExprs overflow

2023-07-09 Thread Yurong via Phabricator via cfe-commits
yronglin created this revision.
Herald added a project: All.
yronglin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Signed-off-by: yrong 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D154784

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Expr.h
  clang/include/clang/AST/Stmt.h
  clang/lib/AST/Expr.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/test/SemaCXX/builtin-dump-struct.cpp

Index: clang/test/SemaCXX/builtin-dump-struct.cpp
===
--- clang/test/SemaCXX/builtin-dump-struct.cpp
+++ clang/test/SemaCXX/builtin-dump-struct.cpp
@@ -159,3 +159,27 @@
 // expected-note@#Format {{no known conversion from 'int' to 'ConstexprString &' for 1st argument}}
 }
 #endif
+
+// Check that PseudoObjectExprBitfields:NumSubExprs doesn't overflow.
+struct t1 {
+  int v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+struct t2 {
+  t1 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16,
+  v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+  v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46,
+  v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61,
+  v62, v63, v64, v65, v66, v67, v68, v69, v70, v71, v72, v73, v74, v75, v76,
+  v77, v78, v79, v80, v81, v82, v83, v84, v85, v86, v87, v88, v89, v90, v91,
+  v92, v93, v94, v95, v96, v97, v98, v99;
+};
+
+int printf(const char *, ...);
+void f1(t2 w) { __builtin_dump_struct(, printf); }
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -1378,8 +1378,15 @@
 void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) {
   VisitExpr(E);
   unsigned numSemanticExprs = Record.readInt();
-  assert(numSemanticExprs + 1 == E->PseudoObjectExprBits.NumSubExprs);
-  E->PseudoObjectExprBits.ResultIndex = Record.readInt();
+  assert(numSemanticExprs + 1 == E->getNumSubExprs());
+
+  unsigned ResultIndex = Record.readInt();
+  if (ResultIndex) {
+E->PseudoObjectExprBits.HasResult = true;
+E->PseudoObjectExprBits.ResultBits.ResultIndex = ResultIndex;
+  } else {
+E->PseudoObjectExprBits.HasResult = false;
+  }
 
   // Read the syntactic expression.
   E->getSubExprsBuffer()[0] = Record.readSubExpr();
Index: clang/lib/AST/Expr.cpp
===
--- clang/lib/AST/Expr.cpp
+++ clang/lib/AST/Expr.cpp
@@ -4848,7 +4848,8 @@
 
 PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
   : Expr(PseudoObjectExprClass, shell) {
-  PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
+  PseudoObjectExprBits.HasResult = false;
+  PseudoObjectExprBits.NumSubExprsIfNoResult = numSemanticExprs + 1;
 }
 
 PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext , Expr *syntax,
@@ -4879,8 +4880,15 @@
Expr *syntax, ArrayRef semantics,
unsigned resultIndex)
 : Expr(PseudoObjectExprClass, type, VK, OK_Ordinary) {
-  PseudoObjectExprBits.NumSubExprs = semantics.size() + 1;
-  PseudoObjectExprBits.ResultIndex = resultIndex + 1;
+  
+  if (resultIndex == NoResult) {
+PseudoObjectExprBits.HasResult = false;
+PseudoObjectExprBits.NumSubExprsIfNoResult = semantics.size() + 1;
+  } else {
+PseudoObjectExprBits.HasResult = true;
+PseudoObjectExprBits.ResultBits.NumSubExprs = semantics.size() + 1;
+PseudoObjectExprBits.ResultBits.ResultIndex = resultIndex + 1;
+  }
 
   for (unsigned i = 0, e = semantics.size() + 1; i != e; ++i) {
 Expr *E = (i == 0 ? syntax : semantics[i-1]);
Index: clang/include/clang/AST/Stmt.h
===
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -591,12 +591,26 @@
 friend class ASTStmtReader; // deserialization
 friend class PseudoObjectExpr;
 
+struct ResultBitfields {
+  // These don't need to be particularly wide, because they're
+  // strictly limited by the forms of expressions we permit.
+  unsigned NumSubExprs : 16;
+  unsigned ResultIndex : 16;
+};
+
 unsigned : NumExprBits;
 
-// These don't need to be particularly 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-07-07 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added inline comments.



Comment at: clang/lib/Sema/SemaExprCXX.cpp:8901-8914
+  // [P2718R0] Lifetime extension in range-based for loops.
+  //
+  // 6.7.7 [class.temporary] p5:
+  // There are four contexts in which temporaries are destroyed at a different
+  // point than the end of the full-expression.
+  //
+  // 6.7.7 [class.temporary] p6:

rsmith wrote:
> This isn't the right way to model the behavior here -- the presence or 
> absence of an `ExprWithCleanups` is just a convenience to tell consumers of 
> the AST whether they should expect to see cleanups later or not, and doesn't 
> carry an implication of affecting the actual temporary lifetimes and storage 
> durations.
> 
> The outcome that we should be aiming to reach is that all 
> `MaterializeTemporaryExpr`s created as part of processing the 
> for-range-initializer are marked as being lifetime-extended by the for-range 
> variable. Probably the simplest way to handle that would be to track the 
> current enclosing for-range-initializer variable in the 
> `ExpressionEvaluationContextRecord`, and whenever a 
> `MaterializeTemporaryExpr` is created, if there is a current enclosing 
> for-range-initializer, mark that `MaterializeTemporaryExpr` as being 
> lifetime-extended by it.
Awesome! Thanks a lot for your advice, this is very helpful! I want to take a 
longer look at it.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-07 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Thanks, landed! I have benefited a lot from your comments!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-07 Thread Yurong via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG36f67434f724: [AST] Stop evaluate constant expression if the 
condition expression which in… (authored by yronglin).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });   
 // expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,12 +5007,13 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
-return ESR_Failed;
-} else {
-  if (!EvaluateInteger(SS->getCond(), Value, Info))
-return ESR_Failed;
+  // We don't know what the value is, and which branch should jump to.
+  EvaluateDependentExpr(SS->getCond(), Info);
+  return ESR_Failed;
 }
+if (!EvaluateInteger(SS->getCond(), Value, Info))
+  return ESR_Failed;
+
 if (!CondScope.destroy())
   return ESR_Failed;
   }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -570,6 +570,9 @@
 - Clang now correctly evaluates ``__has_extension (cxx_defaulted_functions)``
   and ``__has_extension (cxx_default_function_template_args)`` to 1.
   (`#61758 `_)
+- Stop evaluating a constant expression if the condition expression which in
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });// expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,12 +5007,13 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
-return ESR_Failed;
-} else {
-  if (!EvaluateInteger(SS->getCond(), Value, Info))
-return ESR_Failed;
+  // We don't know what the value is, and which branch should jump to.
+  EvaluateDependentExpr(SS->getCond(), Info);
+  return ESR_Failed;
 }
+if (!EvaluateInteger(SS->getCond(), Value, Info))
+  return ESR_Failed;
+
 if (!CondScope.destroy())
   return ESR_Failed;
   }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -570,6 +570,9 @@
 - Clang now correctly evaluates ``__has_extension (cxx_defaulted_functions)``
   and ``__has_extension (cxx_default_function_template_args)`` to 1.
   (`#61758 `_)
+- Stop evaluating a constant expression if the condition expression which in
+  switch statement contains errors.
+  (`#63453 

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-07 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153296#4479718 , @hokein wrote:

> Thanks, this looks good.

Thanks for your review! I don't know why the reversion status still `Needs 
Review`, and the `libcxx ci` often fails to start.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-06 Thread Yurong via Phabricator via cfe-commits
yronglin marked 2 inline comments as done.
yronglin added a comment.

Thanks for your review!




Comment at: clang/lib/AST/ExprConstant.cpp:4914
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());

aaron.ballman wrote:
> rsmith wrote:
> > I don't think the changes to this function are appropriate, because:
> > 
> > 1) The special-casing of `RecoveryExpr` doesn't seem like it can be 
> > correct. There's no guarantee that we get a `RecoveryExpr` any time we 
> > encounter an expression that contains errors; error-dependence can be 
> > propagated from other places, such as types.
> > 2) For other error-dependent expressions, we also can't necessarily compute 
> > a value.
> > 3) It's not the responsibility of this function to deal with the situation 
> > where a value is needed and can't be produced -- the responsibility to 
> > handle that lies with the caller of this function instead. Eg, look at the 
> > handling of `ReturnStmt` or `DoStmt`.
> > 
> > So I think we should undo all the changes in this function, and only fix 
> > `SwitchStmt` to properly handle a value-dependent condition.
> Thank you for the explanation -- this makes more sense to me now. I agree 
> with the suggestion to just change `EvaluateSwitch()`, sorry for the false 
> start!
Thanks! I have undo this change.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-06 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 537929.
yronglin added a comment.

Format


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });   
 // expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,12 +5007,13 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
-return ESR_Failed;
-} else {
-  if (!EvaluateInteger(SS->getCond(), Value, Info))
-return ESR_Failed;
+  // We don't know what the value is, and which branch should jump to.
+  EvaluateDependentExpr(SS->getCond(), Info);
+  return ESR_Failed;
 }
+if (!EvaluateInteger(SS->getCond(), Value, Info))
+  return ESR_Failed;
+
 if (!CondScope.destroy())
   return ESR_Failed;
   }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -568,6 +568,9 @@
 - Clang now correctly evaluates ``__has_extension (cxx_defaulted_functions)``
   and ``__has_extension (cxx_default_function_template_args)`` to 1.
   (`#61758 `_)
+- Stop evaluating a constant expression if the condition expression which in
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });// expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,12 +5007,13 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
-return ESR_Failed;
-} else {
-  if (!EvaluateInteger(SS->getCond(), Value, Info))
-return ESR_Failed;
+  // We don't know what the value is, and which branch should jump to.
+  EvaluateDependentExpr(SS->getCond(), Info);
+  return ESR_Failed;
 }
+if (!EvaluateInteger(SS->getCond(), Value, Info))
+  return ESR_Failed;
+
 if (!CondScope.destroy())
   return ESR_Failed;
   }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -568,6 +568,9 @@
 - Clang now correctly evaluates ``__has_extension (cxx_defaulted_functions)``
   and ``__has_extension (cxx_default_function_template_args)`` to 1.
   (`#61758 `_)
+- Stop evaluating a constant expression if the condition expression which in
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^
___
cfe-commits mailing 

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-06 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 537928.
yronglin marked an inline comment as done.
yronglin added a comment.

Address comments


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });   
 // expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,12 +5007,13 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
-return ESR_Failed;
-} else {
-  if (!EvaluateInteger(SS->getCond(), Value, Info))
-return ESR_Failed;
+  // We don't know what the value is, and which branch should jump to.
+  EvaluateDependentExpr(SS->getCond(), Info);
+  return ESR_Failed;
 }
+if (!EvaluateInteger(SS->getCond(), Value, Info))
+return ESR_Failed;
+   
 if (!CondScope.destroy())
   return ESR_Failed;
   }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -568,6 +568,9 @@
 - Clang now correctly evaluates ``__has_extension (cxx_defaulted_functions)``
   and ``__has_extension (cxx_default_function_template_args)`` to 1.
   (`#61758 `_)
+- Stop evaluating a constant expression if the condition expression which in
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });// expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,12 +5007,13 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
-return ESR_Failed;
-} else {
-  if (!EvaluateInteger(SS->getCond(), Value, Info))
-return ESR_Failed;
+  // We don't know what the value is, and which branch should jump to.
+  EvaluateDependentExpr(SS->getCond(), Info);
+  return ESR_Failed;
 }
+if (!EvaluateInteger(SS->getCond(), Value, Info))
+return ESR_Failed;
+   
 if (!CondScope.destroy())
   return ESR_Failed;
   }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -568,6 +568,9 @@
 - Clang now correctly evaluates ``__has_extension (cxx_defaulted_functions)``
   and ``__has_extension (cxx_default_function_template_args)`` to 1.
   (`#61758 `_)
+- Stop evaluating a constant expression if the condition expression which in
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-06 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added a comment.

Many thanks for all of your comments, I learned a lot from the discussions, 
your incredible depth of knowledge have helped fundamentally shape Clang into a 
great compiler! 
It seems the common denominator is that constant evaluation should stop when we 
encounter a value dependent expression, and return `ESR_Failed`.




Comment at: clang/lib/AST/ExprConstant.cpp:5019
 if (SS->getCond()->isValueDependent()) {
   if (!EvaluateDependentExpr(SS->getCond(), Info))
 return ESR_Failed;

shafik wrote:
> Please don't forget to remove this `if` and make the return unconditional as 
> reinforced by @hokein comment above.
Thanks for your tips!, removed!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-06 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 537714.
yronglin added a comment.

Address comments.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });   
 // expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4913,11 +4913,20 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
-  if (Info.noteSideEffect())
-return true;
+  // Note that we have a side effect that matters for constant evaluation.
+  bool SideEffects = Info.noteSideEffect();
+  // If the reason we're here is because of a recovery expression, we don't
+  // want to continue to evaluate further as we will never know what the actual
+  // value is.
+  if (isa(E))
+return false;
+
+  // Otherwise, return whether we want to continue after noting the side
+  // effects, which should only happen if the expression has errors but isn't
+  // a recovery expression on its own.
   assert(E->containsErrors() && "valid value-dependent expression should never 
"
 "reach invalid code path.");
-  return false;
+  return SideEffects;
 }
 
 /// Evaluate a condition (either a variable declaration or an expression).
@@ -5007,12 +5016,13 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
-return ESR_Failed;
-} else {
-  if (!EvaluateInteger(SS->getCond(), Value, Info))
-return ESR_Failed;
+  // We don't know what the value is, and which branch should jump to.
+  EvaluateDependentExpr(SS->getCond(), Info);
+  return ESR_Failed;
 }
+if (!EvaluateInteger(SS->getCond(), Value, Info))
+return ESR_Failed;
+   
 if (!CondScope.destroy())
   return ESR_Failed;
   }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -568,6 +568,9 @@
 - Clang now correctly evaluates ``__has_extension (cxx_defaulted_functions)``
   and ``__has_extension (cxx_default_function_template_args)`` to 1.
   (`#61758 `_)
+- Stop evaluating a constant expression if the condition expression which in
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -87,6 +87,7 @@
 // We're not checking specific recovery here so don't assert diagnostics.
 TEST_EVALUATE(Switch, switch (!!){});  // expected-error + {{}}
 TEST_EVALUATE(SwitchInit, switch (auto x = !!){}); // expected-error + {{}}
+TEST_EVALUATE(SwitchCondValDep, switch (invalid_value) { default: break; });// expected-error + {{}}
 TEST_EVALUATE(For, for (!!){}); // expected-error + {{}}
 // FIXME: should bail out instead of looping.
 // expected-note@-2 + {{infinite loop}}
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4913,11 +4913,20 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
-  if (Info.noteSideEffect())
-return true;
+  // Note that we have a side effect that matters for constant evaluation.
+  bool SideEffects = Info.noteSideEffect();
+  // If the reason we're here is because of a recovery expression, we don't
+  // want to 

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-04 Thread Yurong via Phabricator via cfe-commits
yronglin added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:4921
+  // value is.
+  if (isa(E))
+return false;

yronglin wrote:
> aaron.ballman wrote:
> > yronglin wrote:
> > > hokein wrote:
> > > > The constant evaluator is not aware of the "error" concept, it is only 
> > > > aware of value-dependent -- the general idea behind is that we treat 
> > > > the dependent-on-error and dependent-on-template-parameters cases the 
> > > > same, they are potentially constant (if we see an expression contains 
> > > > errors, it could be constant depending on how the error is resolved), 
> > > > this will give us nice recovery and avoid bogus following diagnostics.
> > > > 
> > > > So, a `RecoveryExpr` should not result in failure when checking for a 
> > > > potential constant expression.
> > > > 
> > > > I think the right fix is to remove the conditional check `if 
> > > > (!EvaluateDependentExpr(SS->getCond(), Info))` in `EvaluateSwitch`, and 
> > > > return `ESR_Failed` unconditionally (we don't know its value, any 
> > > > switch-case anwser will be wrong in some cases). We already do this for 
> > > > return-statment, do-statement etc.
> > > > 
> > > > 
> > > Do you mean?
> > > ```
> > > if (SS->getCond()->isValueDependent()) {
> > > EvaluateDependentExpr(SS->getCond(), Info);
> > > return ESR_Failed;
> > > }
> > > ```
> > > the general idea behind is that we treat the dependent-on-error and 
> > > dependent-on-template-parameters cases the same, they are potentially 
> > > constant (if we see an expression contains errors, it could be constant 
> > > depending on how the error is resolved), this will give us nice recovery 
> > > and avoid bogus following diagnostics.
> > 
> > I could use some further education on why this is the correct approach. For 
> > a dependent-on-template-parameters case, this makes sense -- either the 
> > template will be instantiated (at which point we'll know if it's a constant 
> > expression) or it won't be (at which point it's constant expression-ness 
> > doesn't matter). But for error recovery, we will *never* get a valid 
> > constant expression.
> > 
> > I worry about the performance overhead of continuing on with constant 
> > expression evaluation in the error case. We use these code paths not only 
> > to get a value but to say "is this a constant expression at all?".
> > 
> > I don't see why the fix should be localized to just the switch statement 
> > condition; it seems like *any* attempt to get a dependent value from an 
> > error recovery expression is a point at which we can definitively say "this 
> > is not a constant expression" and move on.
> I understand that continuing to perform constant evaluation when an error 
> occurs can bring more additional diagnostic information (such as jumping to 
> the default branch to continue calculation when the condition expression 
> evaluation of switch-statement fails), but the additional diagnostic message 
> that is emitted is in some cases doesn't usually useful, and as Aaron said 
> may affect performance of clang. I don't have enough experience to make a 
> tradeoff between the two. BTW 
> https://github.com/llvm/llvm-project/blob/843ff7581408a02e852c0f1f7ebf176cabbc7527/clang/lib/Parse/ParseStmt.cpp#L1894-L1909
>  I don't quite understand why a RecoveryExpr is not created here, which 
> caused to the whole do statement disappears on the 
> AST(https://godbolt.org/z/PsPb31YKP), should we fix this? 
Thanks a lot for your comments! @aaron.ballman 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-04 Thread Yurong via Phabricator via cfe-commits
yronglin marked 3 inline comments as done.
yronglin added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:4921
+  // value is.
+  if (isa(E))
+return false;

aaron.ballman wrote:
> yronglin wrote:
> > hokein wrote:
> > > The constant evaluator is not aware of the "error" concept, it is only 
> > > aware of value-dependent -- the general idea behind is that we treat the 
> > > dependent-on-error and dependent-on-template-parameters cases the same, 
> > > they are potentially constant (if we see an expression contains errors, 
> > > it could be constant depending on how the error is resolved), this will 
> > > give us nice recovery and avoid bogus following diagnostics.
> > > 
> > > So, a `RecoveryExpr` should not result in failure when checking for a 
> > > potential constant expression.
> > > 
> > > I think the right fix is to remove the conditional check `if 
> > > (!EvaluateDependentExpr(SS->getCond(), Info))` in `EvaluateSwitch`, and 
> > > return `ESR_Failed` unconditionally (we don't know its value, any 
> > > switch-case anwser will be wrong in some cases). We already do this for 
> > > return-statment, do-statement etc.
> > > 
> > > 
> > Do you mean?
> > ```
> > if (SS->getCond()->isValueDependent()) {
> > EvaluateDependentExpr(SS->getCond(), Info);
> > return ESR_Failed;
> > }
> > ```
> > the general idea behind is that we treat the dependent-on-error and 
> > dependent-on-template-parameters cases the same, they are potentially 
> > constant (if we see an expression contains errors, it could be constant 
> > depending on how the error is resolved), this will give us nice recovery 
> > and avoid bogus following diagnostics.
> 
> I could use some further education on why this is the correct approach. For a 
> dependent-on-template-parameters case, this makes sense -- either the 
> template will be instantiated (at which point we'll know if it's a constant 
> expression) or it won't be (at which point it's constant expression-ness 
> doesn't matter). But for error recovery, we will *never* get a valid constant 
> expression.
> 
> I worry about the performance overhead of continuing on with constant 
> expression evaluation in the error case. We use these code paths not only to 
> get a value but to say "is this a constant expression at all?".
> 
> I don't see why the fix should be localized to just the switch statement 
> condition; it seems like *any* attempt to get a dependent value from an error 
> recovery expression is a point at which we can definitively say "this is not 
> a constant expression" and move on.
I understand that continuing to perform constant evaluation when an error 
occurs can bring more additional diagnostic information (such as jumping to the 
default branch to continue calculation when the condition expression evaluation 
of switch-statement fails), but the additional diagnostic message that is 
emitted is in some cases doesn't usually useful, and as Aaron said may affect 
performance of clang. I don't have enough experience to make a tradeoff between 
the two. BTW 
https://github.com/llvm/llvm-project/blob/843ff7581408a02e852c0f1f7ebf176cabbc7527/clang/lib/Parse/ParseStmt.cpp#L1894-L1909
 I don't quite understand why a RecoveryExpr is not created here, which caused 
to the whole do statement disappears on the 
AST(https://godbolt.org/z/PsPb31YKP), should we fix this? 


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-04 Thread Yurong via Phabricator via cfe-commits
yronglin marked 3 inline comments as done.
yronglin added a comment.

Thanks a lot for your comments! @hokein




Comment at: clang/lib/AST/ExprConstant.cpp:4921
+  // value is.
+  if (isa(E))
+return false;

hokein wrote:
> The constant evaluator is not aware of the "error" concept, it is only aware 
> of value-dependent -- the general idea behind is that we treat the 
> dependent-on-error and dependent-on-template-parameters cases the same, they 
> are potentially constant (if we see an expression contains errors, it could 
> be constant depending on how the error is resolved), this will give us nice 
> recovery and avoid bogus following diagnostics.
> 
> So, a `RecoveryExpr` should not result in failure when checking for a 
> potential constant expression.
> 
> I think the right fix is to remove the conditional check `if 
> (!EvaluateDependentExpr(SS->getCond(), Info))` in `EvaluateSwitch`, and 
> return `ESR_Failed` unconditionally (we don't know its value, any switch-case 
> anwser will be wrong in some cases). We already do this for return-statment, 
> do-statement etc.
> 
> 
Do you mean?
```
if (SS->getCond()->isValueDependent()) {
EvaluateDependentExpr(SS->getCond(), Info);
return ESR_Failed;
}
```



Comment at: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp:91
+
+static_assert(test13(), "should not crash"); // expected-error {{static 
assertion expression is not an integral constant expression}}
+

hokein wrote:
> nit: we can simplify it with the `TEST_EVALUATE` macro:
> 
> ```
> TEST_EVALUATE(SwitchErrorCond, switch(undef) { case 0: return 7; default: 
> break;})
> ```
Thanks, I will use `TEST_EVALUATE ` to simplify.



Comment at: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp:93
+
+constexpr int test14() {
+int sum = 0;

hokein wrote:
> Is this a new crash (and the tests below)?
> 
> They don't look like new crashes, I think the current constant evaluator 
> should be able to handle them well. IIUC the only crash we have is the case 
> where we have a error-dependent condition in `switch`?
Thanks you for catch this, it's my mistake, I have ever copied these tests from 
the code above.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-03 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 536802.
yronglin added a comment.

Address comment.

- Change `EvaluateDependentExpr`.
- Add more test for do/while/for/return/ctor.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/constexpr-function-recovery-crash.cpp

Index: clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
===
--- clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
+++ clang/test/SemaCXX/constexpr-function-recovery-crash.cpp
@@ -78,6 +78,132 @@
 constexpr int test12() { return "wrong"; } // expected-error {{cannot initialize return object of type 'int'}}
 constexpr int force12 = test12();  // expected-error {{must be initialized by a constant}}
 
+constexpr int test13() {
+switch (invalid_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(test13(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test14() {
+int sum = 0;
+for (int i = 0; i < invalid_value; ++i) // expected-error {{use of undeclared identifier}}
+sum = sum + i;
+return sum;
+}
+
+static_assert(test14(), "should not crash"); // expected-error {{static assertion failed due to requirement}}
+
+constexpr int test15() {
+int sum = 0;
+for (int i = 0; i < 10; i += invalid_value) // expected-error {{use of undeclared identifier}}
+sum = sum + i;
+return sum;
+}
+
+static_assert(test15(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test16() {
+int sum = 0;
+for (int i = invalid_value; i < 10; ++i) // expected-error {{use of undeclared identifier}}
+sum = sum + i;
+return sum;
+}
+
+static_assert(test16(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test17() {
+int sum = 0, i = 0;
+do
+  sum += i;
+while (invalid_value); // expected-error {{use of undeclared identifier}}
+return sum;
+}
+
+static_assert(test17(), "should not crash"); // expected-error {{static assertion failed due to requirement}}
+
+constexpr int test18() {
+  int sum = 0, i = 0;
+  while (invalid_value) // expected-error {{use of undeclared identifier}}
+sum += i;
+  return sum;
+}
+
+static_assert(test18(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test19() {
+struct Test19 {
+int a[2] = {0, 1};
+constexpr const int *begin() const {
+return invalid_value;  // expected-error {{use of undeclared identifier}}
+}
+constexpr const int *end() const {
+return a + 2;
+}
+};
+
+int sum = 0;
+Test19 t;
+for (const auto v : t) {
+sum += v;
+}
+return sum;
+}
+
+static_assert(test19(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test20() {
+struct Test20 {
+int a[2] = {0, 1};
+constexpr const int *begin() const {
+return a;
+}
+constexpr const int *end() const {
+return invalid_value;  // expected-error {{use of undeclared identifier}}
+}
+};
+
+int sum = 0;
+Test20 t;
+for (const auto v : t) {
+sum += v;
+}
+return sum;
+}
+
+static_assert(test20(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test21() {
+  return invalid_value; // expected-error {{use of undeclared identifier}}
+}
+
+static_assert(test21(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test22() {
+  struct Test22 {
+int value = invalid_value; // expected-error {{use of undeclared identifier}}
+  };
+  return Test22().value;
+}
+
+static_assert(test22(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
+constexpr int test23() {
+  struct Test23 {
+int value;
+constexpr Test23(int v) : value(v) {}
+constexpr Test23(int a, int b) : Test23(a * b * invalid_value) {} // expected-error {{use of undeclared identifier}}
+  };
+  return Test23(1, 2).value;
+}
+
+static_assert(test23(), "should not crash"); // expected-error {{static assertion expression is not an integral constant expression}}
+
 #define TEST_EVALUATE(Name, X) \
   constexpr int testEvaluate##Name() { \
 X return 0;\
Index: 

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-03 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153296#4468373 , @aaron.ballman 
wrote:

> In D153296#4459769 , @yronglin 
> wrote:
>
>> Please help me, I have no better idea on this issue, do you have any better 
>> ideas? @erichkeane @shafik
>
> I think what's being suggested is to change `EvaluateDependentExpr()` 
> somewhat along these lines:
>
>   static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
> assert(E->isValueDependent());
>   
> // Note that we have a side effect that matters for constant evaluation.
> bool SideEffects = Info.noteSideEffect();
> // If the reason we're here is because of a recovery expression, we don't
> // want to continue to evaluate further as we will never know what the 
> actual
> // value is.
> if (isa(E))
>   return false;
>   
> // Otherwise, return whether we want to continue after noting the side
> // effects, which should only happen if the expression has errors but 
> isn't
> // a recovery expression on its own.
> assert(E->containsErrors() && "valid value-dependent expression should 
> never "
>   "reach invalid code path.");
> return SideEffects;
>   }
>
> This way, code paths that get down to a `RecoveryExpr` will not continue to 
> evaluate further (as there's really no point -- there's no way to get a 
> reasonable value from from the recovery expression anyway), but the fix isn't 
> specific to just switch statements. After making these changes, you should 
> look for places where `EvaluateDependentExpr()` is being called to try to 
> come up with a test case where that expression is a recovery expression so 
> that we can fill out test coverage beyond just the situation with `switch` 
> from the original report. Does that make sense?
>
> (Marking as requesting changes so it's clear this review isn't yet accepted.)

Thanks a lot! @aaron.ballman , I try to address comments and add more test, 
this case (https://godbolt.org/z/ExPoEKcrf) looks strange, why the do-statement 
missing in the printed AST?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-07-02 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

friendly ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D139586: [Clang][C++23] Lifetime extension in range-based for loops

2023-06-29 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D139586#4403533 , @cor3ntin wrote:

> FYI, I'm not actively working on this, 
> I did mess around with it a bit 
> https://github.com/cor3ntin/llvm-project/commit/478ff7f1aa7a4046fa8b293dfb86489b930a
> but I'm extremely unfamiliar with that part of clang and i have no clue how 
> to write tests.
> Feel free to take over!



In D139586#4403533 , @cor3ntin wrote:

> FYI, I'm not actively working on this, 
> I did mess around with it a bit 
> https://github.com/cor3ntin/llvm-project/commit/478ff7f1aa7a4046fa8b293dfb86489b930a
> but I'm extremely unfamiliar with that part of clang and i have no clue how 
> to write tests.
> Feel free to take over!

Thanks @cor3ntin ! If you are no bandwidth to working on D139586 
, I'd be happy to do take over.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D139586

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-29 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Please help me, I have no better idea on this issue, do you have any better 
idea? @erichkeane @shafik


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-29 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153701#4459036 , @cor3ntin wrote:

> Sorry, I missed the ping on Discord.
> Thanks for working on this
>
> I don't feel qualified to review this, but I don't think there are nearly 
> enough tests.
> FYI there is a previous attempt at this here https://reviews.llvm.org/D139586 
> - with some test suggestions

If you are no bandwidth to working on D139586 
, I'd be happy to do take over.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-29 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153701#4459036 , @cor3ntin wrote:

> Sorry, I missed the ping on Discord.
> Thanks for working on this
>
> I don't feel qualified to review this, but I don't think there are nearly 
> enough tests.
> FYI there is a previous attempt at this here https://reviews.llvm.org/D139586 
> - with some test suggestions

Thank you for take a look!  I'm sorry I have not found D139586 
 already exists, should I close this ticket? 
D139586  seems more complete.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-28 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 535414.
yronglin added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Decl.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CodeGenCXX/for-range-temporaries.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -413,7 +413,7 @@
 
   Lifetime extension in range-based for loops
   https://wg21.link/P2718R0;>P2718R0
-  No
+  Clang 17
 
 
 
Index: clang/test/CodeGenCXX/for-range-temporaries.cpp
===
--- clang/test/CodeGenCXX/for-range-temporaries.cpp
+++ clang/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++20 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EXT-LIFETIME
 
 struct A {
   A();
@@ -103,8 +104,8 @@
 // CHECK: call void @_ZN1BC1Ev(
 // CHECK: call void @_ZN1CC1ERK1B(
 // CHECK: call void @_ZN1DC1ERK1C(
-// CHECK: call void @_ZN1CD1Ev(
-// CHECK: call void @_ZN1BD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // CHECK: call void @_ZN1DC1ERKS_(
 // CHECK: call void @_Z5begin1D(
 // CHECK: call void @_ZN1DD1Ev(
@@ -122,6 +123,8 @@
 // CHECK: [[CLEANUP]]:
 // CHECK: call void @_ZN1ED1Ev(
 // CHECK: call void @_ZN1ED1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // In for-range:
 // call void @_ZN1DD1Ev(
 // CHECK: br label %[[END:.*]]
@@ -142,5 +145,6 @@
 // CHECK: [[END]]:
 // In desugared version:
 // call void @_ZN1DD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1DD1Ev(
 // CHECK: call void @_ZN1AD1Ev(
 // CHECK: ret void
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2529,6 +2529,7 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
+  RangeVar->setCXXForRangeInitializer(true);
   if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
 diag::err_for_range_deduction_failure)) {
 ActOnInitializerError(LoopVar);
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8807,7 +8807,8 @@
 
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
  bool DiscardedValue, bool IsConstexpr,
- bool IsTemplateArgument) {
+ bool IsTemplateArgument,
+ bool 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-28 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

friendly ping~


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-27 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Seems the diagnostic message `:5:9: note: constexpr evaluation hit 
maximum step limit; possible infinite loop?` was redundant, also gcc dose not 
emit this message.

https://godbolt.org/z/v55P88cdT


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-27 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 534920.
yronglin added a comment.

Poke CI


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Decl.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CodeGenCXX/for-range-temporaries.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -413,7 +413,7 @@
 
   Lifetime extension in range-based for loops
   https://wg21.link/P2718R0;>P2718R0
-  No
+  Clang 17
 
 
 
Index: clang/test/CodeGenCXX/for-range-temporaries.cpp
===
--- clang/test/CodeGenCXX/for-range-temporaries.cpp
+++ clang/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++20 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EXT-LIFETIME
 
 struct A {
   A();
@@ -103,8 +104,8 @@
 // CHECK: call void @_ZN1BC1Ev(
 // CHECK: call void @_ZN1CC1ERK1B(
 // CHECK: call void @_ZN1DC1ERK1C(
-// CHECK: call void @_ZN1CD1Ev(
-// CHECK: call void @_ZN1BD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // CHECK: call void @_ZN1DC1ERKS_(
 // CHECK: call void @_Z5begin1D(
 // CHECK: call void @_ZN1DD1Ev(
@@ -122,6 +123,8 @@
 // CHECK: [[CLEANUP]]:
 // CHECK: call void @_ZN1ED1Ev(
 // CHECK: call void @_ZN1ED1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // In for-range:
 // call void @_ZN1DD1Ev(
 // CHECK: br label %[[END:.*]]
@@ -142,5 +145,6 @@
 // CHECK: [[END]]:
 // In desugared version:
 // call void @_ZN1DD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1DD1Ev(
 // CHECK: call void @_ZN1AD1Ev(
 // CHECK: ret void
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2529,6 +2529,7 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
+  RangeVar->setCXXForRangeInitializer(true);
   if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
 diag::err_for_range_deduction_failure)) {
 ActOnInitializerError(LoopVar);
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8807,7 +8807,8 @@
 
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
  bool DiscardedValue, bool IsConstexpr,
- bool IsTemplateArgument) {
+ bool IsTemplateArgument,
+ bool 

[PATCH] D153701: [Clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-26 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 534610.
yronglin added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Decl.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CodeGenCXX/for-range-temporaries.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -413,7 +413,7 @@
 
   Lifetime extension in range-based for loops
   https://wg21.link/P2718R0;>P2718R0
-  No
+  Clang 17
 
 
 
Index: clang/test/CodeGenCXX/for-range-temporaries.cpp
===
--- clang/test/CodeGenCXX/for-range-temporaries.cpp
+++ clang/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++20 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EXT-LIFETIME
 
 struct A {
   A();
@@ -103,8 +104,8 @@
 // CHECK: call void @_ZN1BC1Ev(
 // CHECK: call void @_ZN1CC1ERK1B(
 // CHECK: call void @_ZN1DC1ERK1C(
-// CHECK: call void @_ZN1CD1Ev(
-// CHECK: call void @_ZN1BD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // CHECK: call void @_ZN1DC1ERKS_(
 // CHECK: call void @_Z5begin1D(
 // CHECK: call void @_ZN1DD1Ev(
@@ -122,6 +123,8 @@
 // CHECK: [[CLEANUP]]:
 // CHECK: call void @_ZN1ED1Ev(
 // CHECK: call void @_ZN1ED1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // In for-range:
 // call void @_ZN1DD1Ev(
 // CHECK: br label %[[END:.*]]
@@ -142,5 +145,6 @@
 // CHECK: [[END]]:
 // In desugared version:
 // call void @_ZN1DD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1DD1Ev(
 // CHECK: call void @_ZN1AD1Ev(
 // CHECK: ret void
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2529,6 +2529,7 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
+  RangeVar->setCXXForRangeInitializer(true);
   if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
 diag::err_for_range_deduction_failure)) {
 ActOnInitializerError(LoopVar);
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8807,7 +8807,8 @@
 
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
  bool DiscardedValue, bool IsConstexpr,
- bool IsTemplateArgument) {
+ bool IsTemplateArgument,
+ bool 

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-26 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 534606.
yronglin added a comment.

Address comments


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/switch.cpp


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is 
not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,7 +5007,9 @@
 APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
 APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
   : LHS;
-if (LHS <= Value && Value <= RHS) {
+if (Value.getBitWidth() == LHS.getBitWidth() &&
+Value.getBitWidth() == RHS.getBitWidth() && LHS <= Value &&
+Value <= RHS) {
   Found = SC;
   break;
 }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -531,6 +531,9 @@
 - Fixed a failing assertion when applying an attribute to an anonymous union.
   The assertion was benign outside of asserts builds and would only fire in 
C++.
   (`#48512 _`).
+- Stop evaluating a constant expression if the condition expression which in 
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -5007,7 +5007,9 @@
 APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
 APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
   : LHS;
-if (LHS <= Value && Value <= RHS) {
+if (Value.getBitWidth() == LHS.getBitWidth() &&
+Value.getBitWidth() == RHS.getBitWidth() && LHS <= Value &&
+Value <= RHS) {
   Found = SC;
   break;
 }
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -531,6 +531,9 @@
 - Fixed a failing assertion when applying an attribute to an anonymous union.
   The assertion was benign outside of asserts builds and would only fire in C++.
   (`#48512 _`).
+- Stop evaluating a constant expression if the condition expression which in 
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-26 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

Can we both check `SS->getCond()->containsErrors()` ? Maybe it can avoid 
bitint's effect. WDYT? @erichkeane @shafik


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153701: [clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-26 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 534559.
yronglin added a comment.

Format and rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Decl.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CodeGenCXX/for-range-temporaries.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -413,7 +413,7 @@
 
   Lifetime extension in range-based for loops
   https://wg21.link/P2718R0;>P2718R0
-  No
+  Clang 17
 
 
 
Index: clang/test/CodeGenCXX/for-range-temporaries.cpp
===
--- clang/test/CodeGenCXX/for-range-temporaries.cpp
+++ clang/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++20 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EXT-LIFETIME
 
 struct A {
   A();
@@ -103,8 +104,8 @@
 // CHECK: call void @_ZN1BC1Ev(
 // CHECK: call void @_ZN1CC1ERK1B(
 // CHECK: call void @_ZN1DC1ERK1C(
-// CHECK: call void @_ZN1CD1Ev(
-// CHECK: call void @_ZN1BD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // CHECK: call void @_ZN1DC1ERKS_(
 // CHECK: call void @_Z5begin1D(
 // CHECK: call void @_ZN1DD1Ev(
@@ -122,6 +123,8 @@
 // CHECK: [[CLEANUP]]:
 // CHECK: call void @_ZN1ED1Ev(
 // CHECK: call void @_ZN1ED1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // In for-range:
 // call void @_ZN1DD1Ev(
 // CHECK: br label %[[END:.*]]
@@ -142,5 +145,6 @@
 // CHECK: [[END]]:
 // In desugared version:
 // call void @_ZN1DD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1DD1Ev(
 // CHECK: call void @_ZN1AD1Ev(
 // CHECK: ret void
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2529,6 +2529,7 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
+  RangeVar->setCXXForRangeInitializer(true);
   if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
 diag::err_for_range_deduction_failure)) {
 ActOnInitializerError(LoopVar);
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8807,7 +8807,8 @@
 
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
  bool DiscardedValue, bool IsConstexpr,
- bool IsTemplateArgument) {
+ bool IsTemplateArgument,
+ 

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-24 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153296#612 , @erichkeane 
wrote:

> So I think I'm pretty confident that the only time we would call 
> `EvaluateDependentExpr` is when we are in an error condition, so I'm 
> convinced the fix 'as is' is incorrect.  The check for noteSideEffect records 
> that we HAVE a side effect, then returns if we are OK ignoring them right now.
>
> So since we are in a state where ignoring this error-case is acceptable, I 
> think returning early there is incorrect as well, at least from a 'code 
> correctness' (even if there isn't a reproducer that would matter?).  I think 
> we're in a case where we want to continue in order to ensure we go through 
> the entire flow, so I THINK we should treat this as 'we have a value we don't 
> know, so its just not found', and should fall into the check on 5019 (unless 
> of course, there is a 'default' option!).
>
> So I think that we should be checking if `Value` is valid right after the 
> default check, which lets us fall into the 'default' branch and get 
> additional diagnostics/continued evaluation.  WDYT @shafik / @yronglin ?

Erich, do you mean we do a modification like this?If I'm not misunderstand, I 
think this looks good to me, we can get more diagnostics.

  diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
  index f1f89122d4cc..967695c61df5 100644
  --- a/clang/lib/AST/ExprConstant.cpp
  +++ b/clang/lib/AST/ExprConstant.cpp
  @@ -4984,8 +4984,7 @@ static EvalStmtResult EvaluateSwitch(StmtResult 
, EvalInfo ,
 return ESR_Failed;
   if (SS->getCond()->isValueDependent()) {
 // Stop evaluate if condition expression contains errors.
  -  if (SS->getCond()->containsErrors() ||
  -  !EvaluateDependentExpr(SS->getCond(), Info))
  +  if (!EvaluateDependentExpr(SS->getCond(), Info))
   return ESR_Failed;
   } else {
 if (!EvaluateInteger(SS->getCond(), Value, Info))
  @@ -4995,6 +4994,8 @@ static EvalStmtResult EvaluateSwitch(StmtResult 
, EvalInfo ,
 return ESR_Failed;
 }
   
  +  bool CondHasSideEffects = SS->getCond()->HasSideEffects(Info.getCtx());
  +
 // Find the switch case corresponding to the value of the condition.
 // FIXME: Cache this lookup.
 const SwitchCase *Found = nullptr;
  @@ -5009,7 +5010,7 @@ static EvalStmtResult EvaluateSwitch(StmtResult 
, EvalInfo ,
   APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
   APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
 : LHS;
  -if (LHS <= Value && Value <= RHS) {
  +if (!CondHasSideEffects && LHS <= Value && Value <= RHS) {
 Found = SC;
 break;
   }


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153701: [clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-24 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 534212.
yronglin added a comment.

Update c++ status


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153701

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Decl.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CodeGenCXX/for-range-temporaries.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -413,7 +413,7 @@
 
   Lifetime extension in range-based for loops
   https://wg21.link/P2718R0;>P2718R0
-  No
+  Clang 17
 
 
 
Index: clang/test/CodeGenCXX/for-range-temporaries.cpp
===
--- clang/test/CodeGenCXX/for-range-temporaries.cpp
+++ clang/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++20 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EXT-LIFETIME
 
 struct A {
   A();
@@ -103,8 +104,8 @@
 // CHECK: call void @_ZN1BC1Ev(
 // CHECK: call void @_ZN1CC1ERK1B(
 // CHECK: call void @_ZN1DC1ERK1C(
-// CHECK: call void @_ZN1CD1Ev(
-// CHECK: call void @_ZN1BD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // CHECK: call void @_ZN1DC1ERKS_(
 // CHECK: call void @_Z5begin1D(
 // CHECK: call void @_ZN1DD1Ev(
@@ -122,6 +123,8 @@
 // CHECK: [[CLEANUP]]:
 // CHECK: call void @_ZN1ED1Ev(
 // CHECK: call void @_ZN1ED1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // In for-range:
 // call void @_ZN1DD1Ev(
 // CHECK: br label %[[END:.*]]
@@ -142,5 +145,6 @@
 // CHECK: [[END]]:
 // In desugared version:
 // call void @_ZN1DD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1DD1Ev(
 // CHECK: call void @_ZN1AD1Ev(
 // CHECK: ret void
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2528,6 +2528,7 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
+  RangeVar->setCXXForRangeInitializer(true);
   if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
 diag::err_for_range_deduction_failure)) {
 ActOnInitializerError(LoopVar);
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8806,7 +8806,7 @@
 
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
  bool DiscardedValue, bool IsConstexpr,
- bool IsTemplateArgument) {
+ bool IsTemplateArgument, bool IsForRangeInit) {
   ExprResult 

[PATCH] D153701: [clang] Implement P2718R0 "Lifetime extension in range-based for loops"

2023-06-24 Thread Yurong via Phabricator via cfe-commits
yronglin created this revision.
Herald added a project: All.
yronglin requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Signed-off-by: yronglin 


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153701

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/AST/Decl.h
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/CodeGenCXX/for-range-temporaries.cpp

Index: clang/test/CodeGenCXX/for-range-temporaries.cpp
===
--- clang/test/CodeGenCXX/for-range-temporaries.cpp
+++ clang/test/CodeGenCXX/for-range-temporaries.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-EXT-LIFETIME
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++23 -emit-llvm -o - -UDESUGAR %s | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-EXT-LIFETIME
 
 struct A {
   A();
@@ -103,8 +104,8 @@
 // CHECK: call void @_ZN1BC1Ev(
 // CHECK: call void @_ZN1CC1ERK1B(
 // CHECK: call void @_ZN1DC1ERK1C(
-// CHECK: call void @_ZN1CD1Ev(
-// CHECK: call void @_ZN1BD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-NO-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // CHECK: call void @_ZN1DC1ERKS_(
 // CHECK: call void @_Z5begin1D(
 // CHECK: call void @_ZN1DD1Ev(
@@ -122,6 +123,8 @@
 // CHECK: [[CLEANUP]]:
 // CHECK: call void @_ZN1ED1Ev(
 // CHECK: call void @_ZN1ED1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1CD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1BD1Ev(
 // In for-range:
 // call void @_ZN1DD1Ev(
 // CHECK: br label %[[END:.*]]
@@ -142,5 +145,6 @@
 // CHECK: [[END]]:
 // In desugared version:
 // call void @_ZN1DD1Ev(
+// CHECK-EXT-LIFETIME: call void @_ZN1DD1Ev(
 // CHECK: call void @_ZN1AD1Ev(
 // CHECK: ret void
Index: clang/lib/Sema/SemaStmt.cpp
===
--- clang/lib/Sema/SemaStmt.cpp
+++ clang/lib/Sema/SemaStmt.cpp
@@ -2528,6 +2528,7 @@
   VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
Context.getAutoRRefDeductType(),
std::string("__range") + DepthStr);
+  RangeVar->setCXXForRangeInitializer(true);
   if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
 diag::err_for_range_deduction_failure)) {
 ActOnInitializerError(LoopVar);
Index: clang/lib/Sema/SemaExprCXX.cpp
===
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8806,7 +8806,7 @@
 
 ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC,
  bool DiscardedValue, bool IsConstexpr,
- bool IsTemplateArgument) {
+ bool IsTemplateArgument, bool IsForRangeInit) {
   ExprResult FullExpr = FE;
 
   if (!FullExpr.get())
@@ -8889,13 +8889,28 @@
   //  - Teach the handful of places that iterate over FunctionScopes to
   //stop at the outermost enclosing lexical scope."
   DeclContext *DC = CurContext;
-  while (DC && isa(DC))
+  while (isa_and_nonnull(DC))
 DC = 

[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-22 Thread Yurong via Phabricator via cfe-commits
yronglin added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:4893
+  // Stop evaluate if E is a RecoveryExpr.
+  if (isa(E))
+return false;

yronglin wrote:
> erichkeane wrote:
> > I'd probably suggest `E->containsErrors()` instead, to cover cases where 
> > we're not the 'root' of a recovery expr?  So something like:
> > 
> > `switch(func_call(unknown_value))`
> > 
> > should create a dependent call expr, but would still contain errors.
> Thanks! Use `E->containsErrors()` and added into release note.
Seems check error inside `EvaluateDependentExpr` will missing diagnostic 
messages.

This case was introduced in D84637
```
constexpr int test5() { // expected-error {{constexpr function never produce}}
  for (;; a++); // expected-error {{use of undeclared identifier}}  \
   expected-note {{constexpr evaluation hit maximum step limit; 
possible infinite loop?}}
  return 1;
}
```
```
./main.cpp:2:11: error: use of undeclared identifier 'a'
2 |   for (;; a++); // expected-error {{use of undeclared identifier}}  \
  |   ^
1 error generated.
```
But I think the `infinite loop` diagnostic is unnecessary, should we update the 
test case? WDYT?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-22 Thread Yurong via Phabricator via cfe-commits
yronglin added a comment.

In D153296#4442363 , @erichkeane 
wrote:

> Just a rewording of the message, else LGTM.

Thanks a lot for you're review!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-22 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 533738.
yronglin marked an inline comment as done.
yronglin added a comment.

Update wording.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/switch.cpp


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is 
not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4889,6 +4889,9 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
+  // Stop evaluating if expression contains errors.
+  if (E->containsErrors())
+return false;
   if (Info.noteSideEffect())
 return true;
   assert(E->containsErrors() && "valid value-dependent expression should never 
"
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -520,6 +520,9 @@
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
   (`#38717 _`).
+- Stop evaluating a constant expression if the condition expression which in 
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4889,6 +4889,9 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
+  // Stop evaluating if expression contains errors.
+  if (E->containsErrors())
+return false;
   if (Info.noteSideEffect())
 return true;
   assert(E->containsErrors() && "valid value-dependent expression should never "
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -520,6 +520,9 @@
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
   (`#38717 _`).
+- Stop evaluating a constant expression if the condition expression which in 
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-22 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:4893
+  // Stop evaluate if E is a RecoveryExpr.
+  if (isa(E))
+return false;

erichkeane wrote:
> I'd probably suggest `E->containsErrors()` instead, to cover cases where 
> we're not the 'root' of a recovery expr?  So something like:
> 
> `switch(func_call(unknown_value))`
> 
> should create a dependent call expr, but would still contain errors.
Thanks! Use `E->containsErrors()` and added into release note.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-22 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 533735.
yronglin marked an inline comment as done.
yronglin added a comment.

Add ReleaseNotes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/switch.cpp


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is 
not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4889,6 +4889,9 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
+  // Stop evaluate if expression contains errors.
+  if (E->containsErrors())
+return false;
   if (Info.noteSideEffect())
 return true;
   assert(E->containsErrors() && "valid value-dependent expression should never 
"
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -520,6 +520,9 @@
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
   (`#38717 _`).
+- Stop evaluate constant expression if the condition expression which in 
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4889,6 +4889,9 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
+  // Stop evaluate if expression contains errors.
+  if (E->containsErrors())
+return false;
   if (Info.noteSideEffect())
 return true;
   assert(E->containsErrors() && "valid value-dependent expression should never "
Index: clang/docs/ReleaseNotes.rst
===
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -520,6 +520,9 @@
   type by the default argument promotions, and thus this is UB. Clang's
   behavior now matches GCC's behavior in C++.
   (`#38717 _`).
+- Stop evaluate constant expression if the condition expression which in 
+  switch statement contains errors.
+  (`#63453 _`)
 
 Bug Fixes to Compiler Builtins
 ^^
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-22 Thread Yurong via Phabricator via cfe-commits
yronglin marked an inline comment as done.
yronglin added inline comments.



Comment at: clang/lib/AST/ExprConstant.cpp:4988
+  if (SS->getCond()->containsErrors() ||
+  !EvaluateDependentExpr(SS->getCond(), Info))
 return ESR_Failed;

erichkeane wrote:
> It seems to me that the 'better' solution is to make EvaluateDependentExpr 
> (or one of its children) be RecoveryExpr aware, and result in a failed value 
> instead.  That way we get this 'fix' for more than just switch statements.
Thanks for your review!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

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


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-22 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 533714.
yronglin added a comment.

Address comments


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/switch.cpp


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is 
not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4889,6 +4889,9 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
+  // Stop evaluate if E is a RecoveryExpr.
+  if (isa(E))
+return false;
   if (Info.noteSideEffect())
 return true;
   assert(E->containsErrors() && "valid value-dependent expression should never 
"


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4889,6 +4889,9 @@
 
 static bool EvaluateDependentExpr(const Expr *E, EvalInfo ) {
   assert(E->isValueDependent());
+  // Stop evaluate if E is a RecoveryExpr.
+  if (isa(E))
+return false;
   if (Info.noteSideEffect())
 return true;
   assert(E->containsErrors() && "valid value-dependent expression should never "
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D153296: [AST] Stop evaluate constant expression if the condition expression which in switch statement contains errors

2023-06-20 Thread Yurong via Phabricator via cfe-commits
yronglin updated this revision to Diff 532853.
yronglin added a comment.

Fix test


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D153296

Files:
  clang/lib/AST/ExprConstant.cpp
  clang/test/SemaCXX/switch.cpp


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is 
not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4983,7 +4983,9 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
+  // Stop evaluate if condition expression contains errors.
+  if (SS->getCond()->containsErrors() ||
+  !EvaluateDependentExpr(SS->getCond(), Info))
 return ESR_Failed;
 } else {
   if (!EvaluateInteger(SS->getCond(), Value, Info))


Index: clang/test/SemaCXX/switch.cpp
===
--- clang/test/SemaCXX/switch.cpp
+++ clang/test/SemaCXX/switch.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s
 
 void test() {
   bool x = true;
@@ -146,3 +147,17 @@
 }
 
 } // namespace EmptyEnum
+
+#if __cplusplus >= 201703L
+constexpr int foo(unsigned char c) {
+switch (unknown_value) { // expected-error {{use of undeclared identifier}}
+case 0:
+return 7;
+default:
+break;
+}
+return 0;
+}
+
+static_assert(foo('d')); // expected-error {{static assertion expression is not an integral constant expression}}
+#endif
Index: clang/lib/AST/ExprConstant.cpp
===
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -4983,7 +4983,9 @@
 !EvaluateDecl(Info, SS->getConditionVariable()))
   return ESR_Failed;
 if (SS->getCond()->isValueDependent()) {
-  if (!EvaluateDependentExpr(SS->getCond(), Info))
+  // Stop evaluate if condition expression contains errors.
+  if (SS->getCond()->containsErrors() ||
+  !EvaluateDependentExpr(SS->getCond(), Info))
 return ESR_Failed;
 } else {
   if (!EvaluateInteger(SS->getCond(), Value, Info))
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >