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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
