[clang] 25d6123 - [clang][Interp] Make sure we have a variable scope for initializers

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 13 06:35:46 PDT 2023


Author: Timm Bäder
Date: 2023-04-13T15:35:30+02:00
New Revision: 25d6123854d16370463ba884e750f303d09e9001

URL: https://github.com/llvm/llvm-project/commit/25d6123854d16370463ba884e750f303d09e9001
DIFF: https://github.com/llvm/llvm-project/commit/25d6123854d16370463ba884e750f303d09e9001.diff

LOG: [clang][Interp] Make sure we have a variable scope for initializers

Otherwise, we run into an assertion when trying to use the current
variable scope while creating temporaries for constructor initializers.

Differential Revision: https://reviews.llvm.org/D147534

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeStmtGen.cpp
    clang/test/AST/Interp/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 2c53900111d9b..e20b714120e8d 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -102,6 +102,9 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
       return false;
 
     for (const auto *Init : Ctor->inits()) {
+      // Scope needed for the initializers.
+      BlockScope<Emitter> Scope(this);
+
       const Expr *InitExpr = Init->getInit();
       if (const FieldDecl *Member = Init->getMember()) {
         const Record::Field *F = R->getField(Member);

diff  --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index 39eb65c13342f..745a30bec33bd 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -250,6 +250,78 @@ struct S {
 constexpr S s;
 static_assert(s.m() == 1, "");
 
+namespace InitializerTemporaries {
+  class Bar {
+  private:
+    int a;
+
+  public:
+    constexpr Bar() : a(10) {}
+    constexpr int getA() const { return a; }
+  };
+
+  class Foo {
+  public:
+    int a;
+
+    constexpr Foo() : a(Bar().getA()) {}
+  };
+  constexpr Foo F;
+  static_assert(F.a == 10, "");
+
+
+  /// Needs constexpr destructors.
+#if __cplusplus >= 202002L
+  /// Does
+  ///    Arr[Pos] = Value;
+  ///    ++Pos;
+  /// in its destructor.
+  class BitSetter {
+  private:
+    int *Arr;
+    int &Pos;
+    int Value;
+
+  public:
+    constexpr BitSetter(int *Arr, int &Pos, int Value) :
+      Arr(Arr), Pos(Pos), Value(Value) {}
+
+    constexpr int getValue() const { return 0; }
+    constexpr ~BitSetter() {
+      Arr[Pos] = Value;
+      ++Pos;
+    }
+  };
+
+  class Test {
+    int a, b, c;
+  public:
+    constexpr Test(int *Arr, int &Pos) :
+      a(BitSetter(Arr, Pos, 1).getValue()),
+      b(BitSetter(Arr, Pos, 2).getValue()),
+      c(BitSetter(Arr, Pos, 3).getValue())
+    {}
+  };
+
+
+  constexpr int T(int Index) {
+    int Arr[] = {0, 0, 0};
+    int Pos = 0;
+
+    {
+      auto T = Test(Arr, Pos);
+      // End of scope, should destroy Test.
+    }
+
+    return Arr[Index];
+  }
+
+  static_assert(T(0) == 1);
+  static_assert(T(1) == 2);
+  static_assert(T(2) == 3);
+#endif
+}
+
 #if __cplusplus >= 201703L
 namespace BaseInit {
   class _A {public: int a;};


        


More information about the cfe-commits mailing list