[llvm] f933bbf - [TableGen] Use guarded assert in constexpr functions (#194728)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 29 08:36:12 PDT 2026
Author: Krzysztof Parzyszek
Date: 2026-04-29T10:36:06-05:00
New Revision: f933bbf694b82845d3d25cc4cf77b0486bff1191
URL: https://github.com/llvm/llvm-project/commit/f933bbf694b82845d3d25cc4cf77b0486bff1191
DIFF: https://github.com/llvm/llvm-project/commit/f933bbf694b82845d3d25cc4cf77b0486bff1191.diff
LOG: [TableGen] Use guarded assert in constexpr functions (#194728)
The constexpr functions in question take a scoped enum as an argument
and a switch statement returns a value for each value of the enum. These
are all legal statements in a constexpr function in C++14.
Under constexpr rules, the evaluation of a constexpr function cannot
lead to an evaluation of any prohibited forms of expressions. An
evaluation of the functions being discussed with a valid argument will
terminate at the switch, and an code that follows will not be evaluated.
Using "llvm_unreachable" after the switch should be ok as long as the
expansion of the llvm_unreachable macro does not contain any statements
not allowed to appear in a constexpr function. At the same time, GCC
before v9 did not tolerate any unguarded calls to non-constexpr
functions after the switch.
To avoid using "llvm_unreachable", which can have multiple expansions,
use an assert with an explicit condition that the underlying value of
the argument lies between the minimum and maximum values of the enum.
Added:
Modified:
llvm/test/TableGen/directive1.td
llvm/test/TableGen/directive2.td
llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
Removed:
################################################################################
diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index 3a110eb6644be..fc6a1fcce47e5 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -54,6 +54,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h"
// CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h"
// CHECK-NEXT: #include "llvm/ADT/Sequence.h"
+// CHECK-NEXT: #include "llvm/ADT/STLExtras.h"
// CHECK-NEXT: #include "llvm/ADT/StringRef.h"
// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
// CHECK-NEXT: #include "llvm/Support/Compiler.h"
@@ -142,10 +143,9 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: case TDLD_dira:
// CHECK-NEXT: return Association::None;
// CHECK-NEXT: } // switch (Dir)
-// CHECK-NEXT: #if __clang__ || !__GNUC__ || __GNUC__ >= 9
-// CHECK-NEXT: // GCC < 9 fails to compile this.
-// CHECK-NEXT: llvm_unreachable("Unexpected directive");
-// CHECK-NEXT: #endif
+// CHECK-NEXT: assert(llvm::to_underlying(Dir) >= llvm::to_underlying(Directive::First_) &&
+// CHECK-NEXT: llvm::to_underlying(Dir) <= llvm::to_underlying(Directive::Last_) &&
+// CHECK-NEXT: "Unexpected directive");
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: constexpr Category getDirectiveCategory(Directive Dir) {
@@ -153,10 +153,9 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: case TDLD_dira:
// CHECK-NEXT: return Category::Executable;
// CHECK-NEXT: } // switch (Dir)
-// CHECK-NEXT: #if __clang__ || !__GNUC__ || __GNUC__ >= 9
-// CHECK-NEXT: // GCC < 9 fails to compile this.
-// CHECK-NEXT: llvm_unreachable("Unexpected directive");
-// CHECK-NEXT: #endif
+// CHECK-NEXT: assert(llvm::to_underlying(Dir) >= llvm::to_underlying(Directive::First_) &&
+// CHECK-NEXT: llvm::to_underlying(Dir) <= llvm::to_underlying(Directive::Last_) &&
+// CHECK-NEXT: "Unexpected directive");
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: constexpr SourceLanguage getDirectiveLanguages(Directive D) {
@@ -164,10 +163,9 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: case TDLD_dira:
// CHECK-NEXT: return SourceLanguage::C | SourceLanguage::Fortran;
// CHECK-NEXT: } // switch(D)
-// CHECK-NEXT: #if __clang__ || !__GNUC__ || __GNUC__ >= 9
-// CHECK-NEXT: // GCC < 9 fails to compile this.
-// CHECK-NEXT: llvm_unreachable("Unexpected directive");
-// CHECK-NEXT: #endif
+// CHECK-NEXT: assert(llvm::to_underlying(D) >= llvm::to_underlying(Directive::First_) &&
+// CHECK-NEXT: llvm::to_underlying(D) <= llvm::to_underlying(Directive::Last_) &&
+// CHECK-NEXT: "Unexpected directive");
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: // Enumeration helper functions
diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index b8babcce411a6..edde2d19f5117 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -47,6 +47,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-EMPTY:
// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h"
// CHECK-NEXT: #include "llvm/ADT/Sequence.h"
+// CHECK-NEXT: #include "llvm/ADT/STLExtras.h"
// CHECK-NEXT: #include "llvm/ADT/StringRef.h"
// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
// CHECK-NEXT: #include "llvm/Support/Compiler.h"
@@ -118,10 +119,9 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: case TDLD_dira:
// CHECK-NEXT: return Association::Block;
// CHECK-NEXT: } // switch (Dir)
-// CHECK-NEXT: #if __clang__ || !__GNUC__ || __GNUC__ >= 9
-// CHECK-NEXT: // GCC < 9 fails to compile this.
-// CHECK-NEXT: llvm_unreachable("Unexpected directive");
-// CHECK-NEXT: #endif
+// CHECK-NEXT: assert(llvm::to_underlying(Dir) >= llvm::to_underlying(Directive::First_) &&
+// CHECK-NEXT: llvm::to_underlying(Dir) <= llvm::to_underlying(Directive::Last_) &&
+// CHECK-NEXT: "Unexpected directive");
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: constexpr Category getDirectiveCategory(Directive Dir) {
@@ -129,10 +129,9 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: case TDLD_dira:
// CHECK-NEXT: return Category::Declarative;
// CHECK-NEXT: } // switch (Dir)
-// CHECK-NEXT: #if __clang__ || !__GNUC__ || __GNUC__ >= 9
-// CHECK-NEXT: // GCC < 9 fails to compile this.
-// CHECK-NEXT: llvm_unreachable("Unexpected directive");
-// CHECK-NEXT: #endif
+// CHECK-NEXT: assert(llvm::to_underlying(Dir) >= llvm::to_underlying(Directive::First_) &&
+// CHECK-NEXT: llvm::to_underlying(Dir) <= llvm::to_underlying(Directive::Last_) &&
+// CHECK-NEXT: "Unexpected directive");
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: constexpr SourceLanguage getDirectiveLanguages(Directive D) {
@@ -140,10 +139,9 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: case TDLD_dira:
// CHECK-NEXT: return SourceLanguage::C | SourceLanguage::Fortran;
// CHECK-NEXT: } // switch(D)
-// CHECK-NEXT: #if __clang__ || !__GNUC__ || __GNUC__ >= 9
-// CHECK-NEXT: // GCC < 9 fails to compile this.
-// CHECK-NEXT: llvm_unreachable("Unexpected directive");
-// CHECK-NEXT: #endif
+// CHECK-NEXT: assert(llvm::to_underlying(D) >= llvm::to_underlying(Directive::First_) &&
+// CHECK-NEXT: llvm::to_underlying(D) <= llvm::to_underlying(Directive::Last_) &&
+// CHECK-NEXT: "Unexpected directive");
// CHECK-NEXT: }
// CHECK-EMPTY:
// CHECK-NEXT: // Enumeration helper functions
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index fa3c16213601f..e091cda694f99 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -272,6 +272,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
OS << "#include \"llvm/ADT/Sequence.h\"\n";
+ OS << "#include \"llvm/ADT/STLExtras.h\"\n";
OS << "#include \"llvm/ADT/StringRef.h\"\n";
OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";
OS << "#include \"llvm/Support/Compiler.h\"\n";
@@ -849,10 +850,11 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
}
}
OS << " } // switch (Dir)\n";
- OS << "#if __clang__ || !__GNUC__ || __GNUC__ >= 9\n";
- OS << " // GCC < 9 fails to compile this.\n";
- OS << " llvm_unreachable(\"Unexpected directive\");\n";
- OS << "#endif\n";
+ OS << " assert(llvm::to_underlying(Dir) >= "
+ "llvm::to_underlying(Directive::First_) &&\n";
+ OS << " llvm::to_underlying(Dir) <= "
+ "llvm::to_underlying(Directive::Last_) &&\n";
+ OS << " \"Unexpected directive\");\n";
OS << "}\n";
}
@@ -870,10 +872,11 @@ static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang,
<< ";\n";
}
OS << " } // switch (Dir)\n";
- OS << "#if __clang__ || !__GNUC__ || __GNUC__ >= 9\n";
- OS << " // GCC < 9 fails to compile this.\n";
- OS << " llvm_unreachable(\"Unexpected directive\");\n";
- OS << "#endif\n";
+ OS << " assert(llvm::to_underlying(Dir) >= "
+ "llvm::to_underlying(Directive::First_) &&\n";
+ OS << " llvm::to_underlying(Dir) <= "
+ "llvm::to_underlying(Directive::Last_) &&\n";
+ OS << " \"Unexpected directive\");\n";
OS << "}\n";
}
@@ -898,10 +901,11 @@ static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang,
OS << ";\n";
}
OS << " } // switch(D)\n";
- OS << "#if __clang__ || !__GNUC__ || __GNUC__ >= 9\n";
- OS << " // GCC < 9 fails to compile this.\n";
- OS << " llvm_unreachable(\"Unexpected directive\");\n";
- OS << "#endif\n";
+ OS << " assert(llvm::to_underlying(D) >= "
+ "llvm::to_underlying(Directive::First_) &&\n";
+ OS << " llvm::to_underlying(D) <= "
+ "llvm::to_underlying(Directive::Last_) &&\n";
+ OS << " \"Unexpected directive\");\n";
OS << "}\n";
}
More information about the llvm-commits
mailing list