[clang] 7d876c6 - [clang][Interp] Add 'Invalid' opcode and use it for throw stmts

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 26 00:00:23 PDT 2023


Author: Timm Bäder
Date: 2023-07-26T08:59:53+02:00
New Revision: 7d876c62a306fe09a69a5a923c757d2cae305d0c

URL: https://github.com/llvm/llvm-project/commit/7d876c62a306fe09a69a5a923c757d2cae305d0c
DIFF: https://github.com/llvm/llvm-project/commit/7d876c62a306fe09a69a5a923c757d2cae305d0c.diff

LOG: [clang][Interp] Add 'Invalid' opcode and use it for throw stmts

We will use this opcode for conditionally executed statements that are
invalid in a constant expression.

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

Added: 
    clang/test/AST/Interp/unsupported.cpp

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/ByteCodeExprGen.h
    clang/lib/AST/Interp/ByteCodeStmtGen.cpp
    clang/lib/AST/Interp/ByteCodeStmtGen.h
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Opcodes.td
    clang/test/AST/Interp/records.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index ff40fd3da13f76..bd8e3304c5893b 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -989,6 +989,14 @@ bool ByteCodeExprGen<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) {
   return this->visit(E->getFunctionName());
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) {
+  if (!this->discard(E->getSubExpr()))
+    return false;
+
+  return this->emitInvalid(E);
+}
+
 template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
   if (E->containsErrors())
     return false;

diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index a031aaa9fae1dd..6e29bc32ba3830 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -97,6 +97,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitTypeTraitExpr(const TypeTraitExpr *E);
   bool VisitLambdaExpr(const LambdaExpr *E);
   bool VisitPredefinedExpr(const PredefinedExpr *E);
+  bool VisitCXXThrowExpr(const CXXThrowExpr *E);
 
 protected:
   bool visitExpr(const Expr *E) override;

diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 59ef19be356a67..e5ca5c2ae4c33b 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -243,6 +243,9 @@ bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
     return visitCaseStmt(cast<CaseStmt>(S));
   case Stmt::DefaultStmtClass:
     return visitDefaultStmt(cast<DefaultStmt>(S));
+  case Stmt::GCCAsmStmtClass:
+  case Stmt::MSAsmStmtClass:
+    return visitAsmStmt(cast<AsmStmt>(S));
   case Stmt::NullStmtClass:
     return true;
   default: {
@@ -617,6 +620,11 @@ bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) {
   return this->visitStmt(S->getSubStmt());
 }
 
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitAsmStmt(const AsmStmt *S) {
+  return this->emitInvalid(S);
+}
+
 namespace clang {
 namespace interp {
 

diff  --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h
index bc50b977a6d04f..278e804a803c95 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.h
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h
@@ -67,6 +67,7 @@ class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> {
   bool visitSwitchStmt(const SwitchStmt *S);
   bool visitCaseStmt(const CaseStmt *S);
   bool visitDefaultStmt(const DefaultStmt *S);
+  bool visitAsmStmt(const AsmStmt *S);
 
   bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
 

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 87bcf8130a73b3..8a17322ba6ca55 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1734,6 +1734,14 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
   return true;
 }
 
+/// Just emit a diagnostic. The expression that caused emission of this
+/// op is not valid in a constant context.
+inline bool Invalid(InterpState &S, CodePtr OpPC) {
+  const SourceLocation &Loc = S.Current->getLocation(OpPC);
+  S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 // Read opcode arguments
 //===----------------------------------------------------------------------===//

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 28074a350d05fb..bc81dfedfc6353 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -601,3 +601,6 @@ def Dup : Opcode {
   let Types = [AllTypeClass];
   let HasGroup = 1;
 }
+
+// [] -> []
+def Invalid : Opcode {}

diff  --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp
index b708f5f6a00911..46939fb6d072fa 100644
--- a/clang/test/AST/Interp/records.cpp
+++ b/clang/test/AST/Interp/records.cpp
@@ -325,7 +325,8 @@ namespace InitializerTemporaries {
   struct S {
     constexpr S() {}
     constexpr ~S() noexcept(false) { throw 12; } // expected-error {{cannot use 'throw'}} \
-                                                 // expected-note {{declared here}} \
+                                                 // expected-error {{never produces a constant expression}} \
+                                                 // expected-note 2{{subexpression not valid}} \
                                                  // ref-error {{cannot use 'throw'}} \
                                                  // ref-error {{never produces a constant expression}} \
                                                  // ref-note 2{{subexpression not valid}}
@@ -333,7 +334,8 @@ namespace InitializerTemporaries {
 
   constexpr int f() {
     S{}; // ref-note {{in call to 'S{}.~S()'}}
-    return 12; // expected-note {{undefined function '~S'}}
+    /// FIXME: Wrong source location below.
+    return 12; // expected-note {{in call to '&S{}->~S()'}}
   }
   static_assert(f() == 12); // expected-error {{not an integral constant expression}} \
                             // expected-note {{in call to 'f()'}} \

diff  --git a/clang/test/AST/Interp/unsupported.cpp b/clang/test/AST/Interp/unsupported.cpp
new file mode 100644
index 00000000000000..0182b33a7fdc42
--- /dev/null
+++ b/clang/test/AST/Interp/unsupported.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -fcxx-exceptions -std=c++20 -verify=ref %s
+
+namespace Throw {
+
+  constexpr int ConditionalThrow(bool t) {
+    if (t)
+      throw 4; // expected-note {{subexpression not valid in a constant expression}} \
+               // ref-note {{subexpression not valid in a constant expression}}
+
+    return 0;
+  }
+
+  static_assert(ConditionalThrow(false) == 0, "");
+  static_assert(ConditionalThrow(true) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                                  // expected-note {{in call to 'ConditionalThrow(true)'}} \
+                                                  // ref-error {{not an integral constant expression}} \
+                                                  // ref-note {{in call to 'ConditionalThrow(true)'}}
+
+  constexpr int Throw() { // expected-error {{never produces a constant expression}} \
+                          // ref-error {{never produces a constant expression}}
+    throw 5; // expected-note {{subexpression not valid in a constant expression}} \
+             // ref-note {{subexpression not valid in a constant expression}}
+    return 0;
+  }
+}
+
+namespace Asm {
+  constexpr int ConditionalAsm(bool t) {
+    if (t)
+      asm(""); // expected-note {{subexpression not valid in a constant expression}} \
+               // ref-note {{subexpression not valid in a constant expression}}
+
+    return 0;
+  }
+  static_assert(ConditionalAsm(false) == 0, "");
+  static_assert(ConditionalAsm(true) == 0, ""); // expected-error {{not an integral constant expression}} \
+                                                // expected-note {{in call to 'ConditionalAsm(true)'}} \
+                                                // ref-error {{not an integral constant expression}} \
+                                                // ref-note {{in call to 'ConditionalAsm(true)'}}
+
+
+  constexpr int Asm() { // expected-error {{never produces a constant expression}} \
+                        // ref-error {{never produces a constant expression}}
+    __asm volatile(""); // expected-note {{subexpression not valid in a constant expression}} \
+                        // ref-note {{subexpression not valid in a constant expression}}
+    return 0;
+  }
+}


        


More information about the cfe-commits mailing list