Author: eleviant Date: 2026-05-29T15:22:31+02:00 New Revision: 0fd11e4a83e862fcb48690555015f7da44131075
URL: https://github.com/llvm/llvm-project/commit/0fd11e4a83e862fcb48690555015f7da44131075 DIFF: https://github.com/llvm/llvm-project/commit/0fd11e4a83e862fcb48690555015f7da44131075.diff LOG: Honor two's complement signed overflow with -fms-compatibility (#198538) This matches MSVC behavior, where signed integer overflow follows two's-complement semantics Added: clang/test/CodeGen/wrapv.c Modified: clang/docs/UsersManual.rst clang/include/clang/Driver/CommonArgs.h clang/include/clang/Options/Options.td clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Driver/ToolChains/CommonArgs.cpp clang/lib/Driver/ToolChains/Flang.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/test/CodeGen/ms-intrinsics.c clang/test/Driver/clang_wrapv_opts.c compiler-rt/test/ubsan/TestCases/Integer/shift.cpp compiler-rt/test/ubsan/TestCases/Misc/abs.cpp Removed: ################################################################################ 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 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/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 5dab4af7618fc..025e8e7d7d761 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -4815,7 +4815,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/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index df49877d4bf62..207b9e519a8ea 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7144,10 +7144,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); @@ -7419,6 +7415,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 6f0ac7d5159c1..d0dab119fa6d8 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3392,8 +3392,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, @@ -3426,6 +3427,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/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 60749104252af..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,9 +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)) + } 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/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 diff --git a/clang/test/CodeGen/wrapv.c b/clang/test/CodeGen/wrapv.c new file mode 100644 index 0000000000000..f1d18cfafd2a0 --- /dev/null +++ b/clang/test/CodeGen/wrapv.c @@ -0,0 +1,15 @@ +// 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 +// RUN: %clang_cc1 -ftrapv -fms-compatibility -emit-llvm %s -o - | FileCheck %s --check-prefix=TRAP +// RUN: %clang_cc1 -ftrapv -fwrapv -emit-llvm %s -o - | FileCheck %s --check-prefix=TRAP + +// NOWRAP: %add = add nsw i32 %0, 1 +// WRAP: %add = add i32 %0, 1 +// TRAP: llvm.sadd.with.overflow + +int add1(int x) { + return x + 1; +} 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" 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> _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
