[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