https://github.com/eleviant updated https://github.com/llvm/llvm-project/pull/198538
>From cf3ff26bd18165f92a6dc00fdc985564d24126b3 Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Tue, 19 May 2026 16:26:53 +0200 Subject: [PATCH 1/5] 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 60749104252af..4881d94181111 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 3bf20b61eac00cba34859d7940531af68319f994 Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Tue, 19 May 2026 20:39:19 +0200 Subject: [PATCH 2/5] 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 753e3ac1b74a5..6cea62106a06b 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 4881d94181111..9fc695a74a3c7 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 cba5e8232b37fffe9dcfb1ef92e0b1b2ab6faf79 Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Tue, 19 May 2026 21:28:49 +0200 Subject: [PATCH 3/5] 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 e6dab43e8412be9cd54666c8fa173eecdd9bc1cd Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Wed, 20 May 2026 14:56:40 +0200 Subject: [PATCH 4/5] 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 8d8e00bbaf7d0..8e9f8ed3bc14b 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7121,10 +7121,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); @@ -7396,6 +7392,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 6a0dcfca62c60..c724e6ff595c5 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3390,8 +3390,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, @@ -3424,6 +3425,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 4c722a2e021eb..892a455167205 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -1269,7 +1269,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" >From 393e5d66fad248d3c441992fcbe577abc9fb4b1e Mon Sep 17 00:00:00 2001 From: Evgeny Leviant <[email protected]> Date: Wed, 27 May 2026 12:32:33 +0200 Subject: [PATCH 5/5] Document implicitly enabled frontend options --- clang/docs/UsersManual.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 4c4c4c4aa9706..3392a210f0bb0 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -4189,6 +4189,11 @@ Changing the MSVC compatibility version makes clang behave more like that version of MSVC. For example, ``-fms-compatibility-version=19`` will enable C++14 features and define ``char16_t`` and ``char32_t`` as builtin types. +For compatibility with existing MSVC behavior, ``-fms-compatibility`` also +implicitly enables several other options, including ``-fno-strict-aliasing``, +``-fwrapv`` and ``-fdelayed-template-parsing``. When MSVC compatibility is +set to a version earlier than 19, it also enables ``-fno-threadsafe-statics``. + .. _cxx: C++ Language Features _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
