[clang] [compiler-rt] Define signed int overflow with -fms-compatibility (PR #198538)
via llvm-commits
llvm-commits at lists.llvm.org
Wed May 20 06:02:11 PDT 2026
https://github.com/eleviant updated https://github.com/llvm/llvm-project/pull/198538
>From c76f242584bbb2cefb902d746283ae7025c11c6a Mon Sep 17 00:00:00 2001
From: Evgeny Leviant <eleviant at accesssoftek.com>
Date: Tue, 19 May 2026 16:26:53 +0200
Subject: [PATCH 1/4] Define signed int overflow with -fms-compatibility
It seems that unlike clang, MSVC doesn't treat signed integer overflow
as UB:
https://godbolt.org/z/GYWdjd3Ex
Patch defines SOW, when -fms-compatibility is used.
---
clang/lib/Frontend/CompilerInvocation.cpp | 3 +--
clang/test/CodeGen/ms-intrinsics.c | 4 ++--
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index c6e8644905964..c8f6d269137bd 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -4212,8 +4212,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// Set the handler, if one is specified.
Opts.OverflowHandler =
std::string(Args.getLastArgValue(OPT_ftrapv_handler));
- }
- else if (Args.hasArg(OPT_fwrapv))
+ } else if (Args.hasArg(OPT_fwrapv) || Opts.MSVCCompat)
Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
if (Args.hasArg(OPT_fwrapv_pointer))
Opts.PointerOverflowDefined = true;
diff --git a/clang/test/CodeGen/ms-intrinsics.c b/clang/test/CodeGen/ms-intrinsics.c
index 271aced5e0b7c..8b719ef8cc1fd 100644
--- a/clang/test/CodeGen/ms-intrinsics.c
+++ b/clang/test/CodeGen/ms-intrinsics.c
@@ -504,8 +504,8 @@ unsigned char test_InterlockedCompareExchange128(
}
// CHECK-64: define{{.*}}i8 @test_InterlockedCompareExchange128(ptr{{.*}}%Destination, i64{{[a-z_ ]*}}%ExchangeHigh, i64{{[a-z_ ]*}}%ExchangeLow, ptr{{.*}}%ComparandResult){{.*}}{
// CHECK-64: %incdec.ptr = getelementptr inbounds nuw i8, ptr %Destination, i64 8
-// CHECK-64: %inc = add nsw i64 %ExchangeHigh, 1
-// CHECK-64: %inc1 = add nsw i64 %ExchangeLow, 1
+// CHECK-64: %inc = add i64 %ExchangeHigh, 1
+// CHECK-64: %inc1 = add i64 %ExchangeLow, 1
// CHECK-64: %incdec.ptr2 = getelementptr inbounds nuw i8, ptr %ComparandResult, i64 8
// CHECK-64: [[EH:%[0-9]+]] = zext i64 %inc to i128
// CHECK-64: [[EL:%[0-9]+]] = zext i64 %inc1 to i128
>From 817cac5134fa4226df745b116e200a1367c4d9c2 Mon Sep 17 00:00:00 2001
From: Evgeny Leviant <eleviant at accesssoftek.com>
Date: Tue, 19 May 2026 20:39:19 +0200
Subject: [PATCH 2/4] Allow -fno-wrapv to force UB on signed int overflow
---
clang/include/clang/Options/Options.td | 2 +-
clang/lib/Frontend/CompilerInvocation.cpp | 8 ++++++--
clang/test/CodeGen/wrapv.c | 12 ++++++++++++
3 files changed, 19 insertions(+), 3 deletions(-)
create mode 100644 clang/test/CodeGen/wrapv.c
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 5eeabf4c33b76..72fb9d25ac0b7 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -4808,7 +4808,7 @@ def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>,
Visibility<[ClangOption, CLOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>,
- Visibility<[ClangOption, CLOption, FlangOption]>;
+ Visibility<[ClangOption, CC1Option, CLOption, FlangOption]>;
def fwrapv_pointer : Flag<["-"], "fwrapv-pointer">, Group<f_Group>,
Visibility<[ClangOption, CLOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Treat pointer overflow as two's complement">;
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index c8f6d269137bd..73e91fbe92c21 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3797,7 +3797,10 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_ftrapv);
GenerateArg(Consumer, OPT_ftrapv_handler, Opts.OverflowHandler);
} else if (Opts.SignedOverflowBehavior == LangOptions::SOB_Defined) {
- GenerateArg(Consumer, OPT_fwrapv);
+ if (!Opts.MSVCCompat)
+ GenerateArg(Consumer, OPT_fwrapv);
+ } else if (Opts.MSVCCompat) {
+ GenerateArg(Consumer, OPT_fno_wrapv);
}
if (Opts.PointerOverflowDefined)
GenerateArg(Consumer, OPT_fwrapv_pointer);
@@ -4212,8 +4215,9 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
// Set the handler, if one is specified.
Opts.OverflowHandler =
std::string(Args.getLastArgValue(OPT_ftrapv_handler));
- } else if (Args.hasArg(OPT_fwrapv) || Opts.MSVCCompat)
+ } else if (Args.hasFlag(OPT_fwrapv, OPT_fno_wrapv, Opts.MSVCCompat)) {
Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
+ }
if (Args.hasArg(OPT_fwrapv_pointer))
Opts.PointerOverflowDefined = true;
diff --git a/clang/test/CodeGen/wrapv.c b/clang/test/CodeGen/wrapv.c
new file mode 100644
index 0000000000000..312695c3d25c6
--- /dev/null
+++ b/clang/test/CodeGen/wrapv.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s --check-prefix=NOWRAP
+// RUN: %clang_cc1 -fno-wrapv -emit-llvm %s -o - | FileCheck %s --check-prefix=NOWRAP
+// RUN: %clang_cc1 -fno-wrapv -fms-compatibility -emit-llvm %s -o - | FileCheck %s --check-prefix=NOWRAP
+// RUN: %clang_cc1 -fwrapv -emit-llvm %s -o - | FileCheck %s --check-prefix=WRAP
+// RUN: %clang_cc1 -fms-compatibility -emit-llvm %s -o - | FileCheck %s --check-prefix=WRAP
+
+// NOWRAP: %add = add nsw i32 %0, 1
+// WRAP: %add = add i32 %0, 1
+
+int add1(int x) {
+ return x + 1;
+}
>From 4568841f986ef4da04c4879dd5f1e7630d16352a Mon Sep 17 00:00:00 2001
From: Evgeny Leviant <eleviant at accesssoftek.com>
Date: Tue, 19 May 2026 21:28:49 +0200
Subject: [PATCH 3/4] Attempt to fix Windows builder
---
compiler-rt/test/ubsan/TestCases/Integer/shift.cpp | 8 ++++----
compiler-rt/test/ubsan/TestCases/Misc/abs.cpp | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/compiler-rt/test/ubsan/TestCases/Integer/shift.cpp b/compiler-rt/test/ubsan/TestCases/Integer/shift.cpp
index 50db16dac18ec..3c4f9692b7a33 100644
--- a/compiler-rt/test/ubsan/TestCases/Integer/shift.cpp
+++ b/compiler-rt/test/ubsan/TestCases/Integer/shift.cpp
@@ -1,5 +1,5 @@
-// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t1 && not %run %t1 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
-// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t2 && not %run %t2 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
+// RUN: %clangxx -DLSH_OVERFLOW -fno-wrapv -DOP='<<' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t1 && not %run %t1 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
+// RUN: %clangxx -DLSH_OVERFLOW -fno-wrapv -DOP='<<=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t2 && not %run %t2 2>&1 | FileCheck %s --check-prefix=CHECK-LSH_OVERFLOW
// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t3 && not %run %t3 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t4 && not %run %t4 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
// RUN: %clangxx -DTOO_LOW -DOP='<<=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t5 && not %run %t5 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_LOW
@@ -9,8 +9,8 @@
// RUN: %clangxx -DTOO_HIGH -DOP='<<=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t9 && not %run %t9 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
// RUN: %clangxx -DTOO_HIGH -DOP='>>=' -fsanitize=shift -fno-sanitize-recover=shift %s -o %t10 && not %run %t10 2>&1 | FileCheck %s --check-prefix=CHECK-TOO_HIGH
-// RUN: %clangxx -DLSH_OVERFLOW -DOP='<<' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t12 && %run %t12
-// RUN: %clangxx -DLSH_OVERFLOW -DOP='>>' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t13 && %run %t13
+// RUN: %clangxx -DLSH_OVERFLOW -fno-wrapv -DOP='<<' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t12 && %run %t12
+// RUN: %clangxx -DLSH_OVERFLOW -fno-wrapv -DOP='>>' -fsanitize=shift-exponent -fno-sanitize-recover=shift %s -o %t13 && %run %t13
// RUN: %clangxx -DTOO_LOW -DOP='<<' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t14 && %run %t14
// RUN: %clangxx -DTOO_LOW -DOP='>>' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t15 && %run %t15
// RUN: %clangxx -DTOO_HIGH -DOP='<<' -fsanitize=shift-base -fno-sanitize-recover=shift %s -o %t16 && %run %t16
diff --git a/compiler-rt/test/ubsan/TestCases/Misc/abs.cpp b/compiler-rt/test/ubsan/TestCases/Misc/abs.cpp
index 5f4beec1e6294..30c9891f224f6 100644
--- a/compiler-rt/test/ubsan/TestCases/Misc/abs.cpp
+++ b/compiler-rt/test/ubsan/TestCases/Misc/abs.cpp
@@ -1,7 +1,7 @@
-// RUN: %clangxx -fsanitize=signed-integer-overflow -w %s -O3 -o %t
+// RUN: %clangxx -fno-wrapv -fsanitize=signed-integer-overflow -w %s -O3 -o %t
// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
-// RUN: %clangxx -fsanitize=signed-integer-overflow -fno-sanitize-recover=signed-integer-overflow -w %s -O3 -o %t.abort
+// RUN: %clangxx -fno-wrapv -fsanitize=signed-integer-overflow -fno-sanitize-recover=signed-integer-overflow -w %s -O3 -o %t.abort
// RUN: not %run %t.abort 2>&1 | FileCheck %s --check-prefix=ABORT
#include <limits.h>
>From a1eca4dd0171e4968d9eec65bab4d8b05e0ef9ad Mon Sep 17 00:00:00 2001
From: Evgeny Leviant <eleviant at accesssoftek.com>
Date: Wed, 20 May 2026 14:56:40 +0200
Subject: [PATCH 4/4] Fix rendering of integer overflow options
---
clang/include/clang/Driver/CommonArgs.h | 3 ++-
clang/lib/Driver/ToolChains/Clang.cpp | 8 ++++----
clang/lib/Driver/ToolChains/CommonArgs.cpp | 7 +++++--
clang/lib/Driver/ToolChains/Flang.cpp | 2 +-
clang/test/Driver/clang_wrapv_opts.c | 6 ++++++
5 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h
index 0af1b89425227..34b3d302fe189 100644
--- a/clang/include/clang/Driver/CommonArgs.h
+++ b/clang/include/clang/Driver/CommonArgs.h
@@ -283,7 +283,8 @@ void renderGlobalISelOptions(const Driver &D, const llvm::opt::ArgList &Args,
const llvm::Triple &Triple);
void renderCommonIntegerOverflowOptions(const llvm::opt::ArgList &Args,
- llvm::opt::ArgStringList &CmdArgs);
+ llvm::opt::ArgStringList &CmdArgs,
+ bool IsMSVCCompat);
bool shouldEnableVectorizerAtOLevel(const llvm::opt::ArgList &Args,
bool isSlpVec);
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index bdffa4fdd7e6b..eddff3f66d5fc 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7081,10 +7081,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);
- // Handle -f[no-]wrapv and -f[no-]strict-overflow, which are used by both
- // clang and flang.
- renderCommonIntegerOverflowOptions(Args, CmdArgs);
-
Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
options::OPT_fno_finite_loops);
@@ -7356,6 +7352,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fms-define-stdc");
}
+ // Handle -f[no-]wrapv and -f[no-]strict-overflow, which are used by both
+ // clang and flang.
+ renderCommonIntegerOverflowOptions(Args, CmdArgs, IsMSVCCompat);
+
// -fms-anonymous-structs is disabled by default.
// Determine whether to enable Microsoft named anonymous struct/union support.
// This implements "last flag wins" semantics for -fms-anonymous-structs,
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index 9c2d1955a9e12..48a14cf582d82 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -3394,8 +3394,9 @@ void tools::renderGlobalISelOptions(const Driver &D, const ArgList &Args,
}
void tools::renderCommonIntegerOverflowOptions(const ArgList &Args,
- ArgStringList &CmdArgs) {
- bool use_fwrapv = false;
+ ArgStringList &CmdArgs,
+ bool IsMSVCCompat) {
+ bool use_fwrapv = IsMSVCCompat;
bool use_fwrapv_pointer = false;
for (const Arg *A : Args.filtered(
options::OPT_fstrict_overflow, options::OPT_fno_strict_overflow,
@@ -3428,6 +3429,8 @@ void tools::renderCommonIntegerOverflowOptions(const ArgList &Args,
if (use_fwrapv)
CmdArgs.push_back("-fwrapv");
+ if (!use_fwrapv && IsMSVCCompat)
+ CmdArgs.push_back("-fno-wrapv");
if (use_fwrapv_pointer)
CmdArgs.push_back("-fwrapv-pointer");
}
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index ce503b74295e4..b21b76d23a8c9 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -1242,7 +1242,7 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
}
renderGlobalISelOptions(D, Args, CmdArgs, Triple);
- renderCommonIntegerOverflowOptions(Args, CmdArgs);
+ renderCommonIntegerOverflowOptions(Args, CmdArgs, false);
assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
diff --git a/clang/test/Driver/clang_wrapv_opts.c b/clang/test/Driver/clang_wrapv_opts.c
index 295d8deb0d99d..012d8f5131d5f 100644
--- a/clang/test/Driver/clang_wrapv_opts.c
+++ b/clang/test/Driver/clang_wrapv_opts.c
@@ -18,3 +18,9 @@
// RUN: %clang -### -S -fno-wrapv-pointer -fno-strict-overflow -fno-wrapv -Werror %s 2>&1 | FileCheck -check-prefix=CHECK4-POINTER %s --implicit-check-not="-fwrapv"
// CHECK4-POINTER: "-fwrapv-pointer"
+
+// RUN: %clang -### -S --target=x86_64-windows-msvc -Werror %s 2>&1 | FileCheck -check-prefix=CHECK5 %s
+// CHECK5: "-fwrapv"
+
+// RUN: %clang -### -S -fno-wrapv --target=x86_64-windows-msvc -Werror %s 2>&1 | FileCheck -check-prefix=CHECK6 %s
+// CHECK6: "-fno-wrapv"
More information about the llvm-commits
mailing list