https://github.com/ilovepi updated 
https://github.com/llvm/llvm-project/pull/174894

>From fe13c35178eca2a207912a9c20c7c69c3c6163af Mon Sep 17 00:00:00 2001
From: Paul Kirth <[email protected]>
Date: Wed, 7 Jan 2026 14:30:55 -0800
Subject: [PATCH 1/4] [clang][driver] Expose a frontend option for
 trap-unreachable

We have several issues that list surprising behavior around UB. In many
cases, this causes undesirable control flow, such as execution falling
through to the next function (or whatever is in memory) instead of
remaining within the bounds of the procedure. #174844, #48943, #146791,
and #137741 all discuss a host of related issues. In #174844, it was
mentioned that we have backend support for this for Rust, and at least
one big class of these issues could be addressed by exposing the option
to clang.

This patch adds a new driver option that does just that. For now, we're
leaving this option off by default, though we expect only small
differences in code size or performance as a result if it were to be
enabled. There will be an RFC in the future when we have more confidence
this should be the default configuration.

Fixes #174844
---
 clang/include/clang/Basic/CodeGenOptions.def |  3 +++
 clang/include/clang/Options/Options.td       |  7 +++++++
 clang/lib/CodeGen/BackendUtil.cpp            |  1 +
 clang/lib/Driver/ToolChains/Clang.cpp        |  3 +++
 clang/test/CodeGen/X86/unreachable-trap.c    | 18 ++++++++++++++++++
 clang/test/Driver/clang_f_opts.c             |  5 +++++
 6 files changed, 37 insertions(+)
 create mode 100644 clang/test/CodeGen/X86/unreachable-trap.c

diff --git a/clang/include/clang/Basic/CodeGenOptions.def 
b/clang/include/clang/Basic/CodeGenOptions.def
index baf8b093c10e6..3bf91c56c4cf1 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -430,6 +430,9 @@ CODEGENOPT(DirectAccessExternalData, 1, 0, Benign)
 /// paths that reach the end of a function without executing a required return.
 CODEGENOPT(StrictReturn, 1, 1, Benign)
 
+/// Whether we should use make unreachable trap or not.
+CODEGENOPT(TrapUnreachable, 1, 0, Benign)
+
 /// Whether emit pseudo probes for sample pgo profile collection.
 CODEGENOPT(PseudoProbeForProfiling, 1, 0, Benign)
 
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 2f57a5b13b917..7817c2c5ab67d 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4693,6 +4693,13 @@ defm strict_return : BoolFOption<"strict-return",
             " of a non-void function as unreachable">,
   PosFlag<SetTrue>>;
 
+defm trap_unreachable
+    : BoolFOption<"trap-unreachable", CodeGenOpts<"TrapUnreachable">,
+                  DefaultFalse,
+                  PosFlag<SetTrue, [], [ClangOption, CC1Option],
+                          "Treat unreachable instructions as traps">,
+                  NegFlag<SetFalse>>;
+
 let Flags = [TargetSpecific] in {
 defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer 
authentication intrinsics">;
 defm ptrauth_calls : OptInCC1FFlag<"ptrauth-calls", "Enable signing and 
authentication of all indirect calls">;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp 
b/clang/lib/CodeGen/BackendUtil.cpp
index d411ef1bf8763..acb262f584328 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -468,6 +468,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
   Options.XCOFFReadOnlyPointers = CodeGenOpts.XCOFFReadOnlyPointers;
   Options.VecLib =
       convertDriverVectorLibraryToVectorLibrary(CodeGenOpts.getVecLib());
+  Options.TrapUnreachable = CodeGenOpts.TrapUnreachable;
 
   switch (CodeGenOpts.getSwiftAsyncFramePointer()) {
   case CodeGenOptions::SwiftAsyncFramePointerKind::Auto:
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index 4ca98600d6e93..e76319a3ac563 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5848,6 +5848,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
   Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack,
                     options::OPT_fno_split_stack);
 
+  Args.addOptInFlag(CmdArgs, options::OPT_ftrap_unreachable,
+                    options::OPT_ftrap_unreachable);
+
   // -fprotect-parens=0 is default.
   if (Args.hasFlag(options::OPT_fprotect_parens,
                    options::OPT_fno_protect_parens, false))
diff --git a/clang/test/CodeGen/X86/unreachable-trap.c 
b/clang/test/CodeGen/X86/unreachable-trap.c
new file mode 100644
index 0000000000000..bea34e80dd873
--- /dev/null
+++ b/clang/test/CodeGen/X86/unreachable-trap.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -ftrap-unreachable 
-S  -o - 2>&1 | FileCheck %s --check-prefix=TRAP
+// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -S  -o - 2>&1 | 
FileCheck %s --check-prefix=NOTRAP
+
+// TRAP: ud2
+// NOTRAP-NOT: ud2
+
+[[noreturn]]
+void exit(int);
+
+#define NULL 0
+
+static void test(void) {
+    int *ptr = NULL;
+    *ptr = 0;
+    exit(0);
+}
+
+void foo() { test(); }
diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c
index 5871f1580d6b7..aedbef393abcc 100644
--- a/clang/test/Driver/clang_f_opts.c
+++ b/clang/test/Driver/clang_f_opts.c
@@ -651,3 +651,8 @@
 // RUN: %clang -### --target=x86_64-pc-windows-msvc -fno-strict-aliasing %s 
2>&1 | FileCheck -check-prefix=CHECK-NO-STRICT-ALIASING %s
 // CHECK-STRICT-ALIASING-NOT: -relaxed-aliasing
 // CHECK-NO-STRICT-ALIASING: -relaxed-aliasing
+
+// RUN: %clang -### -ftrap-unreachable %s 2>&1 | FileCheck %s 
-check-prefix=UNREACHABLE-TRAP
+// RUN: %clang -### -fno-trap-unreachable %s 2>&1 | FileCheck %s 
-check-prefix=NO-UNREACHABLE-TRAP
+// UNREACHABLE-TRAP: "-ftrap-unreachable"
+// NO-UNREACHABLE-TRAP-NOT: "-ftrap-unreachable"

>From 8289e84bc3c7e572f625899246949a82d63707b9 Mon Sep 17 00:00:00 2001
From: Paul Kirth <[email protected]>
Date: Mon, 12 Jan 2026 11:53:59 -0800
Subject: [PATCH 2/4] Also support NoTrapAfterNoreturn

---
 clang/include/clang/Basic/CodeGenOptions.def |  6 ++---
 clang/include/clang/Basic/CodeGenOptions.h   |  6 +++++
 clang/include/clang/Options/Options.td       | 13 ++++++-----
 clang/lib/CodeGen/BackendUtil.cpp            | 12 +++++++++-
 clang/lib/Driver/ToolChains/Clang.cpp        |  5 ++---
 clang/test/CodeGen/X86/unreachable-trap.c    | 23 +++++++++++++++-----
 clang/test/Driver/clang_f_opts.c             | 12 ++++++----
 7 files changed, 55 insertions(+), 22 deletions(-)

diff --git a/clang/include/clang/Basic/CodeGenOptions.def 
b/clang/include/clang/Basic/CodeGenOptions.def
index 3bf91c56c4cf1..90303062779b8 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -413,6 +413,9 @@ VALUE_CODEGENOPT(TLSSize, 8, 0, Benign)
 /// The types of variables that we will extend the live ranges of.
 ENUM_CODEGENOPT(ExtendVariableLiveness, ExtendVariableLivenessKind, 2, 
ExtendVariableLivenessKind::None, Benign)
 
+/// Whether we should use make unreachable trap or not.
+ENUM_CODEGENOPT(TrapUnreachable, TrapUnreachableKind, 2, 
TrapUnreachableKind::None, Benign)
+
 /// The default stack protector guard offset to use.
 VALUE_CODEGENOPT(StackProtectorGuardOffset, 32, INT_MAX, Benign)
 
@@ -430,9 +433,6 @@ CODEGENOPT(DirectAccessExternalData, 1, 0, Benign)
 /// paths that reach the end of a function without executing a required return.
 CODEGENOPT(StrictReturn, 1, 1, Benign)
 
-/// Whether we should use make unreachable trap or not.
-CODEGENOPT(TrapUnreachable, 1, 0, Benign)
-
 /// Whether emit pseudo probes for sample pgo profile collection.
 CODEGENOPT(PseudoProbeForProfiling, 1, 0, Benign)
 
diff --git a/clang/include/clang/Basic/CodeGenOptions.h 
b/clang/include/clang/Basic/CodeGenOptions.h
index c60ca507ff917..6265272f9507f 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -126,6 +126,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
     All,
   };
 
+  enum class TrapUnreachableKind {
+    None,
+    ExceptNoreturn,
+    All,
+  };
+
   enum InlineAsmDialectKind {
     IAD_ATT,
     IAD_Intel,
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 7817c2c5ab67d..10a152f4a3c0b 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4693,12 +4693,13 @@ defm strict_return : BoolFOption<"strict-return",
             " of a non-void function as unreachable">,
   PosFlag<SetTrue>>;
 
-defm trap_unreachable
-    : BoolFOption<"trap-unreachable", CodeGenOpts<"TrapUnreachable">,
-                  DefaultFalse,
-                  PosFlag<SetTrue, [], [ClangOption, CC1Option],
-                          "Treat unreachable instructions as traps">,
-                  NegFlag<SetFalse>>;
+def ftrap_unreachable : Joined<["-"], "ftrap-unreachable=">,
+  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Treat unreachable instruction as traps.">,
+  Values<"all,except-noreturn,none">,
+  NormalizedValues<["All", "ExceptNoreturn", "None"]>,
+  NormalizedValuesScope<"CodeGenOptions::TrapUnreachableKind">,
+  MarshallingInfoEnum<CodeGenOpts<"TrapUnreachable">, "None">;
 
 let Flags = [TargetSpecific] in {
 defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer 
authentication intrinsics">;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp 
b/clang/lib/CodeGen/BackendUtil.cpp
index acb262f584328..cacce9f30b48d 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -468,7 +468,17 @@ static bool initTargetOptions(const CompilerInstance &CI,
   Options.XCOFFReadOnlyPointers = CodeGenOpts.XCOFFReadOnlyPointers;
   Options.VecLib =
       convertDriverVectorLibraryToVectorLibrary(CodeGenOpts.getVecLib());
-  Options.TrapUnreachable = CodeGenOpts.TrapUnreachable;
+
+  switch(CodeGenOpts.getTrapUnreachable()){
+  case clang::CodeGenOptions::TrapUnreachableKind::ExceptNoreturn:
+    Options.NoTrapAfterNoreturn = true;
+    LLVM_FALLTHROUGH;
+  case clang::CodeGenOptions::TrapUnreachableKind::All:
+    Options.TrapUnreachable = true;
+    break;
+  case clang::CodeGenOptions::TrapUnreachableKind::None:
+    break;
+  };
 
   switch (CodeGenOpts.getSwiftAsyncFramePointer()) {
   case CodeGenOptions::SwiftAsyncFramePointerKind::Auto:
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index e76319a3ac563..4c3d04a0bbd7f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5848,9 +5848,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
   Args.addOptInFlag(CmdArgs, options::OPT_fsplit_stack,
                     options::OPT_fno_split_stack);
 
-  Args.addOptInFlag(CmdArgs, options::OPT_ftrap_unreachable,
-                    options::OPT_ftrap_unreachable);
-
   // -fprotect-parens=0 is default.
   if (Args.hasFlag(options::OPT_fprotect_parens,
                    options::OPT_fno_protect_parens, false))
@@ -5865,6 +5862,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
   Args.addOptInFlag(CmdArgs, options::OPT_fatomic_ignore_denormal_mode,
                     options::OPT_fno_atomic_ignore_denormal_mode);
 
+  Args.addLastArg(CmdArgs, options::OPT_ftrap_unreachable);
+
   if (Arg *A = Args.getLastArg(options::OPT_fextend_args_EQ)) {
     const llvm::Triple::ArchType Arch = TC.getArch();
     if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
diff --git a/clang/test/CodeGen/X86/unreachable-trap.c 
b/clang/test/CodeGen/X86/unreachable-trap.c
index bea34e80dd873..e7f2adc3f9f9b 100644
--- a/clang/test/CodeGen/X86/unreachable-trap.c
+++ b/clang/test/CodeGen/X86/unreachable-trap.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -ftrap-unreachable 
-S  -o - 2>&1 | FileCheck %s --check-prefix=TRAP
-// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu -S  -o - 2>&1 | 
FileCheck %s --check-prefix=NOTRAP
+// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu 
-ftrap-unreachable=all -S  -o - 2>&1 | FileCheck %s --check-prefixes=TRAP,COMMON
+// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu 
-ftrap-unreachable=except-noreturn -S  -o - 2>&1 | FileCheck %s 
--check-prefixes=NORETURN,COMMON
+// RUN: %clang_cc1 %s -O1 -triple=x86_64-unknown-linux-gnu 
-ftrap-unreachable=none -S  -o - 2>&1 | FileCheck %s 
--check-prefixes=NOTRAP,COMMON
 
-// TRAP: ud2
 // NOTRAP-NOT: ud2
 
 [[noreturn]]
@@ -9,10 +9,23 @@ void exit(int);
 
 #define NULL 0
 
-static void test(void) {
+[[gnu::noinline]]
+[[noreturn]]
+void a() {
+// COMMON-LABEL: a:
+// TRAP: ud2
+// NORETURN: ud2
     int *ptr = NULL;
     *ptr = 0;
     exit(0);
 }
 
-void foo() { test(); }
+[[gnu::noinline]]
+[[noreturn]]
+ void b() {
+// COMMON-LABEL: b:
+// COMMON: call{{.*}} exit
+// TRAP: ud2
+// NORETURN-NOT: ud2
+    exit(0);
+}
diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c
index aedbef393abcc..68db27a2f63d2 100644
--- a/clang/test/Driver/clang_f_opts.c
+++ b/clang/test/Driver/clang_f_opts.c
@@ -652,7 +652,11 @@
 // CHECK-STRICT-ALIASING-NOT: -relaxed-aliasing
 // CHECK-NO-STRICT-ALIASING: -relaxed-aliasing
 
-// RUN: %clang -### -ftrap-unreachable %s 2>&1 | FileCheck %s 
-check-prefix=UNREACHABLE-TRAP
-// RUN: %clang -### -fno-trap-unreachable %s 2>&1 | FileCheck %s 
-check-prefix=NO-UNREACHABLE-TRAP
-// UNREACHABLE-TRAP: "-ftrap-unreachable"
-// NO-UNREACHABLE-TRAP-NOT: "-ftrap-unreachable"
+// RUN: %clang -### -ftrap-unreachable=all %s 2>&1 | FileCheck %s 
-check-prefix=UNREACHABLE-TRAP-ALL
+// RUN: %clang -### -ftrap-unreachable=none %s 2>&1 | FileCheck %s 
-check-prefix=UNREACHABLE-TRAP-NONE
+// RUN: %clang -### -ftrap-unreachable=except-noreturn %s 2>&1 | FileCheck %s 
-check-prefix=UNREACHABLE-TRAP-EXCEPT-NORETURN
+// RUN: %clang -###  %s 2>&1 | FileCheck %s 
-check-prefix=UNREACHABLE-TRAP-EMPTY
+// UNREACHABLE-TRAP-ALL: "-ftrap-unreachable=all"
+// UNREACHABLE-TRAP-EXCEPT-NORETURN: "-ftrap-unreachable=except-noreturn"
+// UNREACHABLE-TRAP-NONE: "-ftrap-unreachable=none"
+// UNREACHABLE-TRAP-EMPTY-NOT: -ftrap-unreachable

>From 713baac7ae3e99f9ddf4ba69943f50e2b2cfd346 Mon Sep 17 00:00:00 2001
From: Paul Kirth <[email protected]>
Date: Mon, 12 Jan 2026 13:08:51 -0800
Subject: [PATCH 3/4] Fix formatting

---
 clang/include/clang/Options/Options.td | 16 +++++++++-------
 clang/lib/CodeGen/BackendUtil.cpp      |  2 +-
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 10a152f4a3c0b..9e74895879fa6 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4693,13 +4693,15 @@ defm strict_return : BoolFOption<"strict-return",
             " of a non-void function as unreachable">,
   PosFlag<SetTrue>>;
 
-def ftrap_unreachable : Joined<["-"], "ftrap-unreachable=">,
-  Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
-  HelpText<"Treat unreachable instruction as traps.">,
-  Values<"all,except-noreturn,none">,
-  NormalizedValues<["All", "ExceptNoreturn", "None"]>,
-  NormalizedValuesScope<"CodeGenOptions::TrapUnreachableKind">,
-  MarshallingInfoEnum<CodeGenOpts<"TrapUnreachable">, "None">;
+def ftrap_unreachable
+    : Joined<["-"], "ftrap-unreachable=">,
+      Group<f_Group>,
+      Visibility<[ClangOption, CC1Option]>,
+      HelpText<"Treat unreachable instruction as traps.">,
+      Values<"all,except-noreturn,none">,
+      NormalizedValues<["All", "ExceptNoreturn", "None"]>,
+      NormalizedValuesScope<"CodeGenOptions::TrapUnreachableKind">,
+      MarshallingInfoEnum<CodeGenOpts<"TrapUnreachable">, "None">;
 
 let Flags = [TargetSpecific] in {
 defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer 
authentication intrinsics">;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp 
b/clang/lib/CodeGen/BackendUtil.cpp
index cacce9f30b48d..3f5f68e444edd 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -469,7 +469,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
   Options.VecLib =
       convertDriverVectorLibraryToVectorLibrary(CodeGenOpts.getVecLib());
 
-  switch(CodeGenOpts.getTrapUnreachable()){
+  switch (CodeGenOpts.getTrapUnreachable()) {
   case clang::CodeGenOptions::TrapUnreachableKind::ExceptNoreturn:
     Options.NoTrapAfterNoreturn = true;
     LLVM_FALLTHROUGH;

>From b864741c6bae28008bfbfd0516d90572fdb111ad Mon Sep 17 00:00:00 2001
From: Paul Kirth <[email protected]>
Date: Tue, 13 Jan 2026 13:17:51 -0800
Subject: [PATCH 4/4] Fix release notes and help text

---
 clang/docs/ReleaseNotes.rst            | 2 ++
 clang/include/clang/Options/Options.td | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 85d2e562d1ecd..b092524a66f7d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -90,6 +90,8 @@ Non-comprehensive list of changes in this release
 
 New Compiler Flags
 ------------------
+- New option ``-ftrap-unreachable`` added to enable the existing backend 
option: TrapUnreachable.
+  This behavior is off by default (e.g. no change in the compiler's behavior) 
for now.
 
 Deprecated Compiler Flags
 -------------------------
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 9e74895879fa6..3cf5fc589979d 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4697,7 +4697,7 @@ def ftrap_unreachable
     : Joined<["-"], "ftrap-unreachable=">,
       Group<f_Group>,
       Visibility<[ClangOption, CC1Option]>,
-      HelpText<"Treat unreachable instruction as traps.">,
+      HelpText<"Replace ``llvm.unreachable`` instructions with traps, when it 
is supported and profitable.">,
       Values<"all,except-noreturn,none">,
       NormalizedValues<["All", "ExceptNoreturn", "None"]>,
       NormalizedValuesScope<"CodeGenOptions::TrapUnreachableKind">,

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to