[clang] 23c39f9 - [clang][Interp] Diagnose unknown parameter values

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 15 04:16:47 PDT 2023


Author: Timm Bäder
Date: 2023-09-15T13:10:19+02:00
New Revision: 23c39f9a9e14caae7b0113e306bf2faf1e4f88f3

URL: https://github.com/llvm/llvm-project/commit/23c39f9a9e14caae7b0113e306bf2faf1e4f88f3
DIFF: https://github.com/llvm/llvm-project/commit/23c39f9a9e14caae7b0113e306bf2faf1e4f88f3.diff

LOG: [clang][Interp] Diagnose unknown parameter values

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/ByteCodeExprGen.cpp
    clang/lib/AST/Interp/Interp.cpp
    clang/lib/AST/Interp/Interp.h
    clang/lib/AST/Interp/Opcodes.td
    clang/test/AST/Interp/c.c
    clang/test/AST/Interp/functions.cpp
    clang/test/AST/Interp/literals.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index e49dc80a5c9ce7c..823bef7a8c19e11 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -2492,7 +2492,8 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
       return this->VisitDeclRefExpr(E);
     }
   }
-  return false;
+
+  return this->emitInvalidDeclRef(E, E);
 }
 
 template <class Emitter>

diff  --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 67fc11d9c9bf9c1..e1951574edb6288 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -542,6 +542,38 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
   return true;
 }
 
+/// We aleady know the given DeclRefExpr is invalid for some reason,
+/// now figure out why and print appropriate diagnostics.
+bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
+  const ValueDecl *D = DR->getDecl();
+  const SourceInfo &E = S.Current->getSource(OpPC);
+
+  if (isa<ParmVarDecl>(D)) {
+    S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
+    S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
+  } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
+    if (!VD->getType().isConstQualified()) {
+      S.FFDiag(E,
+               VD->getType()->isIntegralOrEnumerationType()
+                   ? diag::note_constexpr_ltor_non_const_int
+                   : diag::note_constexpr_ltor_non_constexpr,
+               1)
+          << VD;
+      S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
+      return false;
+    }
+
+    // const, but no initializer.
+    if (!VD->getAnyInitializer()) {
+      S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
+      S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
+      return false;
+    }
+  }
+
+  return false;
+}
+
 bool Interpret(InterpState &S, APValue &Result) {
   // The current stack frame when we started Interpret().
   // This is being used by the ops to determine wheter

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 37d3dd0da6568af..8453856e526a6b2 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -175,6 +175,9 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
                       APFloat::opStatus Status);
 
+/// Checks why the given DeclRefExpr is invalid.
+bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);
+
 /// Interpreter entry point.
 bool Interpret(InterpState &S, APValue &Result);
 
@@ -1854,6 +1857,12 @@ inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {
   return false;
 }
 
+inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,
+                           const DeclRefExpr *DR) {
+  assert(DR);
+  return CheckDeclRef(S, OpPC, DR);
+}
+
 template <PrimType Name, class T = typename PrimConv<Name>::T>
 inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
   llvm::SmallVector<int64_t> ArrayIndices;

diff  --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index e0c7cf1eaf92489..eeb71db125fef73 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -54,6 +54,7 @@ def ArgLETD: ArgType { let Name = "const LifetimeExtendedTemporaryDecl *"; }
 def ArgCastKind : ArgType { let Name = "CastKind"; }
 def ArgCallExpr : ArgType { let Name = "const CallExpr *"; }
 def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; }
+def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; }
 
 //===----------------------------------------------------------------------===//
 // Classes of types instructions operate on.
@@ -632,3 +633,7 @@ def Invalid : Opcode {}
 def InvalidCast : Opcode {
   let Args = [ArgCastKind];
 }
+
+def InvalidDeclRef : Opcode {
+  let Args = [ArgDeclRef];
+}

diff  --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 789139362335236..c0ec5f8339dd1d7 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -3,8 +3,6 @@
 // RUN: %clang_cc1 -verify=ref -std=c11 %s
 // RUN: %clang_cc1 -pedantic -verify=pedantic-ref -std=c11 %s
 
-/// expected-no-diagnostics
-
 _Static_assert(1, "");
 _Static_assert(0 != 1, "");
 _Static_assert(1.0 == 1.0, ""); // pedantic-ref-warning {{not an integer constant expression}} \
@@ -26,3 +24,15 @@ const int b = 3;
 _Static_assert(b == 3, ""); // pedantic-ref-warning {{not an integer constant expression}} \
                             // pedantic-expected-warning {{not an integer constant expression}}
 
+const int c; // ref-note {{declared here}} \
+             // pedantic-ref-note {{declared here}} \
+             // expected-note {{declared here}} \
+             // pedantic-expected-note {{declared here}}
+_Static_assert(c == 0, ""); // ref-error {{not an integral constant expression}} \
+                            // ref-note {{initializer of 'c' is unknown}} \
+                            // pedantic-ref-error {{not an integral constant expression}} \
+                            // pedantic-ref-note {{initializer of 'c' is unknown}} \
+                            // expected-error {{not an integral constant expression}} \
+                            // expected-note {{initializer of 'c' is unknown}} \
+                            // pedantic-expected-error {{not an integral constant expression}} \
+                            // pedantic-expected-note {{initializer of 'c' is unknown}}

diff  --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp
index e1dd73b6958688a..331df74d50b3d62 100644
--- a/clang/test/AST/Interp/functions.cpp
+++ b/clang/test/AST/Interp/functions.cpp
@@ -1,5 +1,9 @@
 // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -std=c++14 -fexperimental-new-constant-interpreter -verify %s
+// RUN: %clang_cc1 -std=c++20 -fexperimental-new-constant-interpreter -verify %s
 // RUN: %clang_cc1 -verify=ref %s
+// RUN: %clang_cc1 -std=c++14 -verify=ref %s
+// RUN: %clang_cc1 -std=c++20 -verify=ref %s
 
 constexpr void doNothing() {}
 constexpr int gimme5() {
@@ -307,3 +311,24 @@ namespace VoidReturn {
   }
   static_assert((foo(),1) == 1, "");
 }
+
+namespace InvalidReclRefs {
+  void param(bool b) { // ref-note {{declared here}} \
+                       // expected-note {{declared here}}
+    static_assert(b, ""); // ref-error {{not an integral constant expression}} \
+                          // ref-note {{function parameter 'b' with unknown value}} \
+                          // expected-error {{not an integral constant expression}} \
+                          // expected-note {{function parameter 'b' with unknown value}}
+    static_assert(true ? true : b, "");
+  }
+
+#if __cplusplus >= 202002L
+  consteval void param2(bool b) { // ref-note {{declared here}} \
+                                 // expected-note {{declared here}}
+    static_assert(b, ""); // ref-error {{not an integral constant expression}} \
+                          // ref-note {{function parameter 'b' with unknown value}} \
+                          // expected-error {{not an integral constant expression}} \
+                          // expected-note {{function parameter 'b' with unknown value}}
+  }
+#endif
+}

diff  --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 1a12413f3f0fa8e..562090d46b094d9 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1088,3 +1088,31 @@ namespace PointerCasts {
   int array[(intptr_t)(char*)0]; // ref-warning {{variable length array folded to constant array}} \
                                  // expected-warning {{variable length array folded to constant array}}
 }
+
+namespace InvalidDeclRefs {
+  bool b00; // ref-note {{declared here}} \
+            // expected-note {{declared here}}
+  static_assert(b00, ""); // ref-error {{not an integral constant expression}} \
+                          // ref-note {{read of non-const variable}} \
+                          // expected-error {{not an integral constant expression}} \
+                          // expected-note {{read of non-const variable}}
+
+  float b01; // ref-note {{declared here}} \
+             // expected-note {{declared here}}
+  static_assert(b01, ""); // ref-error {{not an integral constant expression}} \
+                          // ref-note {{read of non-constexpr variable}} \
+                          // expected-error {{not an integral constant expression}} \
+                          // expected-note {{read of non-constexpr variable}}
+
+  extern const int b02; // ref-note {{declared here}} \
+                        // expected-note {{declared here}}
+  static_assert(b02, ""); // ref-error {{not an integral constant expression}} \
+                          // ref-note {{initializer of 'b02' is unknown}} \
+                          // expected-error {{not an integral constant expression}} \
+                          // expected-note {{initializer of 'b02' is unknown}}
+
+  /// FIXME: This should also be diagnosed in the new interpreter.
+  int b03 = 3; // ref-note {{declared here}}
+  static_assert(b03, ""); // ref-error {{not an integral constant expression}} \
+                          // ref-note {{read of non-const variable}}
+}


        


More information about the cfe-commits mailing list