[clang] 92417f2 - [clang][Interp] Record initialization via conditional operator

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 6 00:44:27 PDT 2023


Author: Timm Bäder
Date: 2023-04-06T09:44:02+02:00
New Revision: 92417f2d4b1706326717cc5e782f3aa77a7157bb

URL: https://github.com/llvm/llvm-project/commit/92417f2d4b1706326717cc5e782f3aa77a7157bb
DIFF: https://github.com/llvm/llvm-project/commit/92417f2d4b1706326717cc5e782f3aa77a7157bb.diff

LOG: [clang][Interp] Record initialization via conditional operator

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/test/AST/Interp/constexpr-nqueens.cpp
    clang/test/AST/Interp/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index e620b4f9b2f63..2f9f99cc06489 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -560,32 +560,8 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator(
     const AbstractConditionalOperator *E) {
-  const Expr *Condition = E->getCond();
-  const Expr *TrueExpr = E->getTrueExpr();
-  const Expr *FalseExpr = E->getFalseExpr();
-
-  LabelTy LabelEnd = this->getLabel();   // Label after the operator.
-  LabelTy LabelFalse = this->getLabel(); // Label for the false expr.
-
-  if (!this->visit(Condition))
-    return false;
-  if (!this->jumpFalse(LabelFalse))
-    return false;
-
-  if (!this->visit(TrueExpr))
-    return false;
-  if (!this->jump(LabelEnd))
-    return false;
-
-  this->emitLabel(LabelFalse);
-
-  if (!this->visit(FalseExpr))
-    return false;
-
-  this->fallthrough(LabelEnd);
-  this->emitLabel(LabelEnd);
-
-  return true;
+  return this->visitConditional(
+      E, [this](const Expr *E) { return this->visit(E); });
 }
 
 template <class Emitter>
@@ -921,6 +897,41 @@ bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
   }
 }
 
+/// Visit a conditional operator, i.e. `A ? B : C`.
+/// \V determines what function to call for the B and C expressions.
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitConditional(
+    const AbstractConditionalOperator *E,
+    llvm::function_ref<bool(const Expr *)> V) {
+
+  const Expr *Condition = E->getCond();
+  const Expr *TrueExpr = E->getTrueExpr();
+  const Expr *FalseExpr = E->getFalseExpr();
+
+  LabelTy LabelEnd = this->getLabel();   // Label after the operator.
+  LabelTy LabelFalse = this->getLabel(); // Label for the false expr.
+
+  if (!this->visit(Condition))
+    return false;
+  if (!this->jumpFalse(LabelFalse))
+    return false;
+
+  if (!V(TrueExpr))
+    return false;
+  if (!this->jump(LabelEnd))
+    return false;
+
+  this->emitLabel(LabelFalse);
+
+  if (!V(FalseExpr))
+    return false;
+
+  this->fallthrough(LabelEnd);
+  this->emitLabel(LabelEnd);
+
+  return true;
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, const Expr *E) {
   switch (T) {
@@ -1429,6 +1440,10 @@ bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
     return this->visitInitializer(CE->getSubExpr());
   } else if (const auto *CE = dyn_cast<CXXBindTemporaryExpr>(Initializer)) {
     return this->visitInitializer(CE->getSubExpr());
+  } else if (const auto *ACO =
+                 dyn_cast<AbstractConditionalOperator>(Initializer)) {
+    return this->visitConditional(
+        ACO, [this](const Expr *E) { return this->visitRecordInitializer(E); });
   }
 
   return false;

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 46a926bfb5f01..85588c6ecd3c1 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -181,6 +181,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
     return this->emitPopPtr(I);
   }
 
+  bool visitConditional(const AbstractConditionalOperator *E,
+                        llvm::function_ref<bool(const Expr *)> V);
+
   /// Creates a local primitive value.
   unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsMutable,
                                   bool IsExtended = false);

diff  --git a/clang/test/AST/Interp/constexpr-nqueens.cpp b/clang/test/AST/Interp/constexpr-nqueens.cpp
index 5aeb7afcd79ce..c71092af069bb 100644
--- a/clang/test/AST/Interp/constexpr-nqueens.cpp
+++ b/clang/test/AST/Interp/constexpr-nqueens.cpp
@@ -17,7 +17,8 @@ struct Board {
   constexpr Board(uint64_t State, bool Failed = false) :
     Failed(Failed) {}
   constexpr Board addQueen(int Row, int Col) const {
-    return Board(State | ((uint64_t)Row << (Col * 4))); // ref-note {{read of uninitialized object}}
+    return Board(State | ((uint64_t)Row << (Col * 4))); // ref-note {{read of uninitialized object}} \
+                                                        // expected-note {{read of object outside its lifetime}}
   }
   constexpr int getQueenRow(int Col) const {
     return (State >> (Col * 4)) & 0xf;
@@ -47,17 +48,22 @@ constexpr Board tryBoard(const Board &Try,
 constexpr Board buildBoardScan(int N, int Col, int Row, const Board &B) {
   return Row == N ? Board(0, true) :
          B.ok(Row, Col) ?
-         tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)), // ref-note {{in call to '&Board()->addQueen(0, 0)}}
+         tryBoard(buildBoardRecurse(N, Col + 1, B.addQueen(Row, Col)), // ref-note {{in call to '&Board()->addQueen(0, 0)}} \
+                                                                       // expected-note {{in call to '&Board()->addQueen(0, 0)}}
                   N, Col, Row+1, B) :
          buildBoardScan(N, Col, Row + 1, B);
 }
 constexpr Board buildBoardRecurse(int N, int Col, const Board &B) {
-  return Col == N ? B : buildBoardScan(N, Col, 0, B); // ref-note {{in call to 'buildBoardScan(8, 0, 0, Board())'}}
+  return Col == N ? B : buildBoardScan(N, Col, 0, B); // ref-note {{in call to 'buildBoardScan(8, 0, 0, Board())'}} \
+                                                      // expected-note {{in call to 'buildBoardScan(8, 0, 0, Board())'}}
+
 }
 constexpr Board buildBoard(int N) {
-  return buildBoardRecurse(N, 0, Board()); // ref-note {{in call to 'buildBoardRecurse(8, 0, Board())'}}
+  return buildBoardRecurse(N, 0, Board()); // ref-note {{in call to 'buildBoardRecurse(8, 0, Board())'}} \
+                                           // expected-note {{in call to 'buildBoardRecurse(8, 0, Board())'}}
 }
 
 constexpr Board q8 = buildBoard(8); // ref-error {{must be initialized by a constant expression}} \
                                     // ref-note {{in call to 'buildBoard(8)'}} \
-                                    // expected-error {{must be initialized by a constant expression}}
+                                    // expected-error {{must be initialized by a constant expression}} \
+                                    // expected-note {{in call to 'buildBoard(8)'}}

diff  --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index a7085e45ca332..39eb65c13342f 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -368,3 +368,14 @@ namespace EmptyCtor {
   constexpr piecewise_construct_t piecewise_construct =
     piecewise_construct_t();
 };
+
+namespace ConditionalInit {
+  struct S { int a; };
+
+  constexpr S getS(bool b) {
+    return b ? S{12} : S{13};
+  }
+
+  static_assert(getS(true).a == 12, "");
+  static_assert(getS(false).a == 13, "");
+};


        


More information about the cfe-commits mailing list