[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