[Clang] Add -fwrapv-pointer flag (#122486)
GCC supports three flags related to overflow behavior: * `-fwrapv`: Makes signed integer overflow well-defined. * `-fwrapv-pointer`: Makes pointer overflow well-defined. * `-fno-strict-overflow`: Implies `-fwrapv -fwrapv-pointer`, making both signed integer overflow and pointer overflow well-defined. Clang currently only supports `-fno-strict-overflow` and `-fwrapv`, but not `-fwrapv-pointer`. This PR proposes to introduce `-fwrapv-pointer` and adjust the semantics of `-fwrapv` to match GCC. This allows signed integer overflow and pointer overflow to be controlled independently, while `-fno-strict-overflow` still exists to control both at the same time (and that option is consistent across GCC and Clang).
This commit is contained in:
parent
458542f454
commit
1295aa2e81
@ -79,7 +79,15 @@ code bases.
|
||||
Undefined behavior due to pointer addition overflow can be reliably detected
|
||||
using ``-fsanitize=pointer-overflow``. It is also possible to use
|
||||
``-fno-strict-overflow`` to opt-in to a language dialect where signed integer
|
||||
and pointer overflow are well-defined.
|
||||
and pointer overflow are well-defined. Since Clang 20, it is also possible
|
||||
to use ``-fwrapv-pointer`` to only make pointer overflow well-defined, while
|
||||
not affecting the behavior of signed integer overflow.
|
||||
|
||||
- The ``-fwrapv`` flag now only makes signed integer overflow well-defined,
|
||||
without affecting pointer overflow, which is controlled by a new
|
||||
``-fwrapv-pointer`` flag. The ``-fno-strict-overflow`` flag now implies
|
||||
both ``-fwrapv`` and ``-fwrapv-pointer`` and as such retains its old meaning.
|
||||
The new behavior matches GCC.
|
||||
|
||||
C/C++ Language Potentially Breaking Changes
|
||||
-------------------------------------------
|
||||
@ -521,6 +529,11 @@ New Compiler Flags
|
||||
- clang-cl and clang-dxc now support ``-fdiagnostics-color=[auto|never|always]``
|
||||
in addition to ``-f[no-]color-diagnostics``.
|
||||
|
||||
- The new ``-fwrapv-pointer`` flag opts-in to a language dialect where pointer
|
||||
overflow is well-defined. The ``-fwrapv`` flag previously implied
|
||||
``-fwrapv-pointer`` as well, but no longer does. ``-fno-strict-overflow``
|
||||
implies ``-fwrapv -fwrapv-pointer``. The flags now match GCC.
|
||||
|
||||
Deprecated Compiler Flags
|
||||
-------------------------
|
||||
|
||||
|
@ -407,6 +407,7 @@ VALUE_LANGOPT(TrivialAutoVarInitMaxSize, 32, 0,
|
||||
"stop trivial automatic variable initialization if var size exceeds the specified size (in bytes). Must be greater than 0.")
|
||||
ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined,
|
||||
"signed integer overflow handling")
|
||||
LANGOPT(PointerOverflowDefined, 1, 0, "make pointer overflow defined")
|
||||
ENUM_LANGOPT(ThreadModel , ThreadModelKind, 2, ThreadModelKind::POSIX, "Thread Model")
|
||||
|
||||
BENIGN_LANGOPT(ArrowDepth, 32, 256,
|
||||
|
@ -4301,6 +4301,11 @@ def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>,
|
||||
HelpText<"Treat signed integer overflow as two's complement">;
|
||||
def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>,
|
||||
Visibility<[ClangOption, 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">;
|
||||
def fno_wrapv_pointer : Flag<["-"], "fno-wrapv-pointer">, Group<f_Group>,
|
||||
Visibility<[ClangOption, CLOption, FlangOption]>;
|
||||
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>,
|
||||
Visibility<[ClangOption, CC1Option]>,
|
||||
HelpText<"Store string literals as writable data">,
|
||||
|
@ -22284,7 +22284,7 @@ RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) {
|
||||
// By adding the mask, we ensure that align_up on an already aligned
|
||||
// value will not change the value.
|
||||
if (Args.Src->getType()->isPointerTy()) {
|
||||
if (getLangOpts().isSignedOverflowDefined())
|
||||
if (getLangOpts().PointerOverflowDefined)
|
||||
SrcForMask =
|
||||
Builder.CreateGEP(Int8Ty, SrcForMask, Args.Mask, "over_boundary");
|
||||
else
|
||||
|
@ -4318,14 +4318,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
// GEP indexes are signed, and scaling an index isn't permitted to
|
||||
// signed-overflow, so we use the same semantics for our explicit
|
||||
// multiply. We suppress this if overflow is not undefined behavior.
|
||||
if (getLangOpts().isSignedOverflowDefined()) {
|
||||
if (getLangOpts().PointerOverflowDefined) {
|
||||
Idx = Builder.CreateMul(Idx, numElements);
|
||||
} else {
|
||||
Idx = Builder.CreateNSWMul(Idx, numElements);
|
||||
}
|
||||
|
||||
Addr = emitArraySubscriptGEP(*this, Addr, Idx, vla->getElementType(),
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
!getLangOpts().PointerOverflowDefined,
|
||||
SignedIndices, E->getExprLoc());
|
||||
|
||||
} else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){
|
||||
@ -4415,7 +4415,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
QualType arrayType = Array->getType();
|
||||
Addr = emitArraySubscriptGEP(
|
||||
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
|
||||
E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
|
||||
E->getType(), !getLangOpts().PointerOverflowDefined, SignedIndices,
|
||||
E->getExprLoc(), &arrayType, E->getBase());
|
||||
EltBaseInfo = ArrayLV.getBaseInfo();
|
||||
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
|
||||
@ -4424,10 +4424,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
|
||||
Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
|
||||
auto *Idx = EmitIdxAfterBase(/*Promote*/true);
|
||||
QualType ptrType = E->getBase()->getType();
|
||||
Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(),
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
SignedIndices, E->getExprLoc(), &ptrType,
|
||||
E->getBase());
|
||||
Addr = emitArraySubscriptGEP(
|
||||
*this, Addr, Idx, E->getType(), !getLangOpts().PointerOverflowDefined,
|
||||
SignedIndices, E->getExprLoc(), &ptrType, E->getBase());
|
||||
}
|
||||
|
||||
LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo);
|
||||
@ -4572,11 +4571,11 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
|
||||
: llvm::ConstantInt::get(IntPtrTy, ConstLength);
|
||||
Idx = Builder.CreateAdd(LowerBoundVal, LengthVal, "lb_add_len",
|
||||
/*HasNUW=*/false,
|
||||
!getLangOpts().isSignedOverflowDefined());
|
||||
!getLangOpts().PointerOverflowDefined);
|
||||
if (Length && LowerBound) {
|
||||
Idx = Builder.CreateSub(
|
||||
Idx, llvm::ConstantInt::get(IntPtrTy, /*V=*/1), "idx_sub_1",
|
||||
/*HasNUW=*/false, !getLangOpts().isSignedOverflowDefined());
|
||||
/*HasNUW=*/false, !getLangOpts().PointerOverflowDefined);
|
||||
}
|
||||
} else
|
||||
Idx = llvm::ConstantInt::get(IntPtrTy, ConstLength + ConstLowerBound);
|
||||
@ -4602,7 +4601,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
|
||||
Length->getType()->hasSignedIntegerRepresentation());
|
||||
Idx = Builder.CreateSub(
|
||||
LengthVal, llvm::ConstantInt::get(IntPtrTy, /*V=*/1), "len_sub_1",
|
||||
/*HasNUW=*/false, !getLangOpts().isSignedOverflowDefined());
|
||||
/*HasNUW=*/false, !getLangOpts().PointerOverflowDefined);
|
||||
} else {
|
||||
ConstLength = ConstLength.zextOrTrunc(PointerWidthInBits);
|
||||
--ConstLength;
|
||||
@ -4629,12 +4628,12 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
|
||||
// GEP indexes are signed, and scaling an index isn't permitted to
|
||||
// signed-overflow, so we use the same semantics for our explicit
|
||||
// multiply. We suppress this if overflow is not undefined behavior.
|
||||
if (getLangOpts().isSignedOverflowDefined())
|
||||
if (getLangOpts().PointerOverflowDefined)
|
||||
Idx = Builder.CreateMul(Idx, NumElements);
|
||||
else
|
||||
Idx = Builder.CreateNSWMul(Idx, NumElements);
|
||||
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, VLA->getElementType(),
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
!getLangOpts().PointerOverflowDefined,
|
||||
/*signedIndices=*/false, E->getExprLoc());
|
||||
} else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) {
|
||||
// If this is A[i] where A is an array, the frontend will have decayed the
|
||||
@ -4654,7 +4653,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
|
||||
// Propagate the alignment from the array itself to the result.
|
||||
EltPtr = emitArraySubscriptGEP(
|
||||
*this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx},
|
||||
ResultExprTy, !getLangOpts().isSignedOverflowDefined(),
|
||||
ResultExprTy, !getLangOpts().PointerOverflowDefined,
|
||||
/*signedIndices=*/false, E->getExprLoc());
|
||||
BaseInfo = ArrayLV.getBaseInfo();
|
||||
TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy);
|
||||
@ -4663,7 +4662,7 @@ LValue CodeGenFunction::EmitArraySectionExpr(const ArraySectionExpr *E,
|
||||
emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, TBAAInfo, BaseTy,
|
||||
ResultExprTy, IsLowerBound);
|
||||
EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy,
|
||||
!getLangOpts().isSignedOverflowDefined(),
|
||||
!getLangOpts().PointerOverflowDefined,
|
||||
/*signedIndices=*/false, E->getExprLoc());
|
||||
}
|
||||
|
||||
|
@ -3043,7 +3043,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
llvm::Value *numElts = CGF.getVLASize(vla).NumElts;
|
||||
if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize");
|
||||
llvm::Type *elemTy = CGF.ConvertTypeForMem(vla->getElementType());
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
if (CGF.getLangOpts().PointerOverflowDefined)
|
||||
value = Builder.CreateGEP(elemTy, value, numElts, "vla.inc");
|
||||
else
|
||||
value = CGF.EmitCheckedInBoundsGEP(
|
||||
@ -3054,7 +3054,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
} else if (type->isFunctionType()) {
|
||||
llvm::Value *amt = Builder.getInt32(amount);
|
||||
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
if (CGF.getLangOpts().PointerOverflowDefined)
|
||||
value = Builder.CreateGEP(CGF.Int8Ty, value, amt, "incdec.funcptr");
|
||||
else
|
||||
value =
|
||||
@ -3066,7 +3066,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
} else {
|
||||
llvm::Value *amt = Builder.getInt32(amount);
|
||||
llvm::Type *elemTy = CGF.ConvertTypeForMem(type);
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
if (CGF.getLangOpts().PointerOverflowDefined)
|
||||
value = Builder.CreateGEP(elemTy, value, amt, "incdec.ptr");
|
||||
else
|
||||
value = CGF.EmitCheckedInBoundsGEP(
|
||||
@ -3179,7 +3179,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
llvm::Value *sizeValue =
|
||||
llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity());
|
||||
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
if (CGF.getLangOpts().PointerOverflowDefined)
|
||||
value = Builder.CreateGEP(CGF.Int8Ty, value, sizeValue, "incdec.objptr");
|
||||
else
|
||||
value = CGF.EmitCheckedInBoundsGEP(
|
||||
@ -4075,7 +4075,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
|
||||
// signed-overflow, so we use the same semantics for our explicit
|
||||
// multiply. We suppress this if overflow is not undefined behavior.
|
||||
llvm::Type *elemTy = CGF.ConvertTypeForMem(vla->getElementType());
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined()) {
|
||||
if (CGF.getLangOpts().PointerOverflowDefined) {
|
||||
index = CGF.Builder.CreateMul(index, numElements, "vla.index");
|
||||
pointer = CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
|
||||
} else {
|
||||
@ -4096,7 +4096,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF,
|
||||
else
|
||||
elemTy = CGF.ConvertTypeForMem(elementType);
|
||||
|
||||
if (CGF.getLangOpts().isSignedOverflowDefined())
|
||||
if (CGF.getLangOpts().PointerOverflowDefined)
|
||||
return CGF.Builder.CreateGEP(elemTy, pointer, index, "add.ptr");
|
||||
|
||||
return CGF.EmitCheckedInBoundsGEP(
|
||||
|
@ -575,6 +575,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
|
||||
options::OPT_fstrict_overflow, false);
|
||||
if (Args.hasFlagNoClaim(options::OPT_fwrapv, options::OPT_fno_wrapv, S))
|
||||
Add &= ~SanitizerKind::SignedIntegerOverflow;
|
||||
if (Args.hasFlagNoClaim(options::OPT_fwrapv_pointer,
|
||||
options::OPT_fno_wrapv_pointer, S))
|
||||
Add &= ~SanitizerKind::PointerOverflow;
|
||||
}
|
||||
Add &= Supported;
|
||||
|
||||
|
@ -3095,12 +3095,19 @@ void tools::renderCommonIntegerOverflowOptions(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) {
|
||||
// -fno-strict-overflow implies -fwrapv if it isn't disabled, but
|
||||
// -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
|
||||
bool StrictOverflow = Args.hasFlag(options::OPT_fstrict_overflow,
|
||||
options::OPT_fno_strict_overflow, true);
|
||||
if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
|
||||
if (A->getOption().matches(options::OPT_fwrapv))
|
||||
CmdArgs.push_back("-fwrapv");
|
||||
} else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
|
||||
options::OPT_fno_strict_overflow)) {
|
||||
if (A->getOption().matches(options::OPT_fno_strict_overflow))
|
||||
CmdArgs.push_back("-fwrapv");
|
||||
} else if (!StrictOverflow) {
|
||||
CmdArgs.push_back("-fwrapv");
|
||||
}
|
||||
if (Arg *A = Args.getLastArg(options::OPT_fwrapv_pointer,
|
||||
options::OPT_fno_wrapv_pointer)) {
|
||||
if (A->getOption().matches(options::OPT_fwrapv_pointer))
|
||||
CmdArgs.push_back("-fwrapv-pointer");
|
||||
} else if (!StrictOverflow) {
|
||||
CmdArgs.push_back("-fwrapv-pointer");
|
||||
}
|
||||
}
|
||||
|
@ -3721,6 +3721,8 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
|
||||
} else if (Opts.SignedOverflowBehavior == LangOptions::SOB_Defined) {
|
||||
GenerateArg(Consumer, OPT_fwrapv);
|
||||
}
|
||||
if (Opts.PointerOverflowDefined)
|
||||
GenerateArg(Consumer, OPT_fwrapv_pointer);
|
||||
|
||||
if (Opts.MSCompatibilityVersion != 0) {
|
||||
unsigned Major = Opts.MSCompatibilityVersion / 10000000;
|
||||
@ -4138,6 +4140,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
||||
}
|
||||
else if (Args.hasArg(OPT_fwrapv))
|
||||
Opts.setSignedOverflowBehavior(LangOptions::SOB_Defined);
|
||||
if (Args.hasArg(OPT_fwrapv_pointer))
|
||||
Opts.PointerOverflowDefined = true;
|
||||
|
||||
Opts.MSCompatibilityVersion = 0;
|
||||
if (const Arg *A = Args.getLastArg(OPT_fms_compatibility_version)) {
|
||||
|
@ -11798,7 +11798,7 @@ static std::optional<bool> isTautologicalBoundsCheck(Sema &S, const Expr *LHS,
|
||||
const Expr *RHS,
|
||||
BinaryOperatorKind Opc) {
|
||||
if (!LHS->getType()->isPointerType() ||
|
||||
S.getLangOpts().isSignedOverflowDefined())
|
||||
S.getLangOpts().PointerOverflowDefined)
|
||||
return std::nullopt;
|
||||
|
||||
// Canonicalize to >= or < predicate.
|
||||
|
@ -1,7 +1,7 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=DEFAULT
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv | FileCheck %s --check-prefix=WRAPV
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=TRAPV
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefixes=CATCH_UB,CATCH_UB_POINTER
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow | FileCheck %s --check-prefixes=CATCH_UB,NOCATCH_UB_POINTER
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fsanitize=signed-integer-overflow -fwrapv | FileCheck %s --check-prefixes=CATCH_UB,NOCATCH_UB_POINTER
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv -ftrapv-handler foo | FileCheck %s --check-prefix=TRAPV_HANDLER
|
||||
|
||||
@ -57,14 +57,14 @@ void test1(void) {
|
||||
// TRAPV_HANDLER: foo(
|
||||
--a;
|
||||
|
||||
// -fwrapv should turn off inbounds for GEP's, PR9256
|
||||
// -fwrapv does not affect inbounds for GEP's.
|
||||
// This is controlled by -fwrapv-pointer instead.
|
||||
extern int* P;
|
||||
++P;
|
||||
// DEFAULT: getelementptr inbounds nuw i32, ptr
|
||||
// WRAPV: getelementptr i32, ptr
|
||||
// WRAPV: getelementptr inbounds nuw i32, ptr
|
||||
// TRAPV: getelementptr inbounds nuw i32, ptr
|
||||
// CATCH_UB_POINTER: getelementptr inbounds nuw i32, ptr
|
||||
// NOCATCH_UB_POINTER: getelementptr i32, ptr
|
||||
// NOCATCH_UB_POINTER: getelementptr inbounds nuw i32, ptr
|
||||
|
||||
// PR9350: char pre-increment never overflows.
|
||||
extern volatile signed char PR9350_char_inc;
|
||||
|
12
clang/test/CodeGen/pointer-overflow.c
Normal file
12
clang/test/CodeGen/pointer-overflow.c
Normal file
@ -0,0 +1,12 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s --check-prefix=DEFAULT
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv | FileCheck %s --check-prefix=DEFAULT
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -ftrapv | FileCheck %s --check-prefix=DEFAULT
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - -fwrapv-pointer | FileCheck %s --check-prefix=FWRAPV-POINTER
|
||||
|
||||
void test(void) {
|
||||
// -fwrapv-pointer should turn off inbounds for GEP's
|
||||
extern int* P;
|
||||
++P;
|
||||
// DEFAULT: getelementptr inbounds nuw i32, ptr
|
||||
// FWRAPV-POINTER: getelementptr i32, ptr
|
||||
}
|
@ -1,11 +1,20 @@
|
||||
// RUN: %clang -### -S -fwrapv -fno-wrapv -fwrapv %s 2>&1 | FileCheck -check-prefix=CHECK1 %s
|
||||
// CHECK1: -fwrapv
|
||||
// RUN: %clang -### -S -fwrapv -fno-wrapv -fwrapv -Werror %s 2>&1 | FileCheck -check-prefix=CHECK1 %s
|
||||
// CHECK1: "-fwrapv"
|
||||
//
|
||||
// RUN: %clang -### -S -fstrict-overflow -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
|
||||
// CHECK2: -fwrapv
|
||||
// RUN: %clang -### -S -fwrapv-pointer -fno-wrapv-pointer -fwrapv-pointer -Werror %s 2>&1 | FileCheck -check-prefix=CHECK1-POINTER %s
|
||||
// CHECK1-POINTER: "-fwrapv-pointer"
|
||||
//
|
||||
// RUN: %clang -### -S -fwrapv -fstrict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK3 %s
|
||||
// CHECK3: -fwrapv
|
||||
// RUN: %clang -### -S -fstrict-overflow -fno-strict-overflow -Werror %s 2>&1 | FileCheck -check-prefix=CHECK2 %s
|
||||
// CHECK2: "-fwrapv"{{.*}}"-fwrapv-pointer"
|
||||
//
|
||||
// RUN: %clang -### -S -fno-wrapv -fno-strict-overflow %s 2>&1 | FileCheck -check-prefix=CHECK4 %s
|
||||
// CHECK4-NOT: -fwrapv
|
||||
// RUN: %clang -### -S -fwrapv -fstrict-overflow -Werror -Werror %s 2>&1 | FileCheck -check-prefix=CHECK3 %s --implicit-check-not="-fwrapv-pointer"
|
||||
// CHECK3: "-fwrapv"
|
||||
//
|
||||
// RUN: %clang -### -S -fwrapv-pointer -fstrict-overflow -Werror %s 2>&1 | FileCheck -check-prefix=CHECK3-POINTER %s --implicit-check-not="-fwrapv"
|
||||
// CHECK3-POINTER: "-fwrapv-pointer"
|
||||
//
|
||||
// RUN: %clang -### -S -fno-wrapv -fno-strict-overflow -Werror %s 2>&1 | FileCheck -check-prefix=CHECK4 %s --implicit-check-not="-fwrapv"
|
||||
// CHECK4: "-fwrapv-pointer"
|
||||
//
|
||||
// RUN: %clang -### -S -fno-wrapv-pointer -fno-strict-overflow -Werror %s 2>&1 | FileCheck -check-prefix=CHECK4-POINTER %s --implicit-check-not="-fwrapv-pointer"
|
||||
// CHECK4-POINTER: "-fwrapv"
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -fwrapv -verify=fwrapv %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -fwrapv-pointer -verify=fwrapv %s
|
||||
|
||||
// fwrapv-no-diagnostics
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user