[clang] c49c386 - [clang][Interp] Reject StmtExprs containing return statements
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 2 03:15:40 PDT 2024
Author: Timm Bäder
Date: 2024-07-02T12:15:24+02:00
New Revision: c49c386caaf7132908995749fed4894cfa1b62d1
URL: https://github.com/llvm/llvm-project/commit/c49c386caaf7132908995749fed4894cfa1b62d1
DIFF: https://github.com/llvm/llvm-project/commit/c49c386caaf7132908995749fed4894cfa1b62d1.diff
LOG: [clang][Interp] Reject StmtExprs containing return statements
Added:
Modified:
clang/lib/AST/Interp/Compiler.cpp
clang/lib/AST/Interp/Compiler.h
clang/lib/AST/Interp/Interp.h
clang/lib/AST/Interp/Opcodes.td
clang/test/AST/Interp/literals.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 3d9c72e2b6dee..739a65070b21d 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -154,6 +154,19 @@ template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
CaseMap OldCaseLabels;
};
+template <class Emitter> class StmtExprScope final {
+public:
+ StmtExprScope(Compiler<Emitter> *Ctx) : Ctx(Ctx), OldFlag(Ctx->InStmtExpr) {
+ Ctx->InStmtExpr = true;
+ }
+
+ ~StmtExprScope() { Ctx->InStmtExpr = OldFlag; }
+
+private:
+ Compiler<Emitter> *Ctx;
+ bool OldFlag;
+};
+
} // namespace interp
} // namespace clang
@@ -3028,6 +3041,7 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
template <class Emitter>
bool Compiler<Emitter>::VisitStmtExpr(const StmtExpr *E) {
BlockScope<Emitter> BS(this);
+ StmtExprScope<Emitter> SS(this);
const CompoundStmt *CS = E->getSubStmt();
const Stmt *Result = CS->getStmtExprResult();
@@ -4056,6 +4070,9 @@ bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) {
template <class Emitter>
bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
+ if (this->InStmtExpr)
+ return this->emitUnsupported(RS);
+
if (const Expr *RE = RS->getRetValue()) {
ExprScope<Emitter> RetScope(this);
if (ReturnType) {
diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h
index 67bd7efb3b091..d28526c76fe13 100644
--- a/clang/lib/AST/Interp/Compiler.h
+++ b/clang/lib/AST/Interp/Compiler.h
@@ -39,6 +39,7 @@ template <class Emitter> class SourceLocScope;
template <class Emitter> class LoopScope;
template <class Emitter> class LabelScope;
template <class Emitter> class SwitchScope;
+template <class Emitter> class StmtExprScope;
template <class Emitter> class Compiler;
struct InitLink {
@@ -334,6 +335,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
friend class LoopScope<Emitter>;
friend class LabelScope<Emitter>;
friend class SwitchScope<Emitter>;
+ friend class StmtExprScope<Emitter>;
/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
@@ -398,6 +400,8 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
/// Flag indicating if return value is to be discarded.
bool DiscardResult = false;
+ bool InStmtExpr = false;
+
/// Flag inidicating if we're initializing an already created
/// variable. This is set in visitInitializer().
bool Initializing = false;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index ff6d50ab9b6f8..328db219ca628 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -2618,6 +2618,13 @@ inline bool Invalid(InterpState &S, CodePtr OpPC) {
return false;
}
+inline bool Unsupported(InterpState &S, CodePtr OpPC) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
+ S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)
+ << S.Current->getRange(OpPC);
+ return false;
+}
+
/// Do nothing and just abort execution.
inline bool Error(InterpState &S, CodePtr OpPC) { return false; }
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 81e7b812da237..8d01fe1ac2bd1 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -714,6 +714,7 @@ def Dup : Opcode {
// [] -> []
def Invalid : Opcode {}
+def Unsupported : Opcode {}
def Error : Opcode {}
def InvalidCast : Opcode {
let Args = [ArgCastKind];
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 3abaf89e8bd01..f70ca79e216da 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1255,4 +1255,14 @@ constexpr int StmtExprEval() {
return 1;
}
static_assert(StmtExprEval() == 2, "");
+
+constexpr int ReturnInStmtExpr() { // both-error {{never produces a constant expression}}
+ return ({
+ return 1; // both-note 2{{this use of statement expressions is not supported in a constant expression}}
+ 2;
+ });
+}
+static_assert(ReturnInStmtExpr() == 1, ""); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
#endif
More information about the cfe-commits
mailing list