Factor out (some of) the checking for invalid forms of pointer

arithmetic into a couple of common routines. Use these to make the
messages more consistent in the various contexts, especially in terms of
consistently diagnosing binary operators with invalid types on both the
left- and right-hand side. Also, improve the grammar and wording of the
messages some, handling both two pointers and two (different) types.

The wording of function pointer arithmetic diagnostics still strikes me
as poorly phrased, and I worry this makes them slightly more awkward if
more consistent. I'm hoping to fix that with a follow-on patch and test
case that will also make them more helpful when a typedef or template
type parameter makes the type completely opaque.

Suggestions on better wording are very welcome, thanks to Richard Smith
for some initial help on that front.

llvm-svn: 133906
This commit is contained in:
Chandler Carruth 2011-06-27 08:02:19 +00:00
parent a61df3f843
commit c933221826
10 changed files with 182 additions and 154 deletions

View File

@ -2900,11 +2900,12 @@ def err_ivar_reference_type : Error<
def err_typecheck_illegal_increment_decrement : Error< def err_typecheck_illegal_increment_decrement : Error<
"cannot %select{decrement|increment}1 value of type %0">; "cannot %select{decrement|increment}1 value of type %0">;
def err_typecheck_arithmetic_incomplete_type : Error< def err_typecheck_arithmetic_incomplete_type : Error<
"arithmetic on pointer to incomplete type %0">; "arithmetic on a pointer to an incomplete type %0">;
def err_typecheck_pointer_arith_function_type : Error< def err_typecheck_pointer_arith_function_type : Error<
"arithmetic on pointer to function type %0">; "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 "
"function type%select{|s}2 %1%select{| and %3}2">;
def err_typecheck_pointer_arith_void_type : Error< def err_typecheck_pointer_arith_void_type : Error<
"arithmetic on pointer to void type">; "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">;
def err_typecheck_decl_incomplete_type : Error< def err_typecheck_decl_incomplete_type : Error<
"variable has incomplete type %0">; "variable has incomplete type %0">;
def ext_typecheck_decl_incomplete_type : ExtWarn< def ext_typecheck_decl_incomplete_type : ExtWarn<
@ -3092,9 +3093,11 @@ def note_forward_class : Note<
def err_duplicate_property : Error< def err_duplicate_property : Error<
"property has a previous declaration">; "property has a previous declaration">;
def ext_gnu_void_ptr : Extension< def ext_gnu_void_ptr : Extension<
"use of GNU void* extension">, InGroup<PointerArith>; "arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">,
InGroup<PointerArith>;
def ext_gnu_ptr_func_arith : Extension< def ext_gnu_ptr_func_arith : Extension<
"arithmetic on pointer to function type %0 is a GNU extension">, "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function "
"type%select{|s}2 %1%select{| and %3}2 is a GNU extension">,
InGroup<PointerArith>; InGroup<PointerArith>;
def error_readonly_property_assignment : Error< def error_readonly_property_assignment : Error<
"assigning to property with 'readonly' attribute not allowed">; "assigning to property with 'readonly' attribute not allowed">;

View File

@ -3092,8 +3092,9 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) { if (ResultType->isVoidType() && !getLangOptions().CPlusPlus) {
// GNU extension: subscripting on pointer to void // GNU extension: subscripting on pointer to void
// FIXME: Use a better warning for this.
Diag(LLoc, diag::ext_gnu_void_ptr) Diag(LLoc, diag::ext_gnu_void_ptr)
<< BaseExpr->getSourceRange(); << 0 << BaseExpr->getSourceRange();
// C forbids expressions of unqualified void type from being l-values. // C forbids expressions of unqualified void type from being l-values.
// See IsCForbiddenLValueType. // See IsCForbiddenLValueType.
@ -5595,6 +5596,145 @@ QualType Sema::CheckRemainderOperands(
return compType; return compType;
} }
/// \brief Diagnose invalid arithmetic on two void pointers.
static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
S.Diag(Loc, S.getLangOptions().CPlusPlus
? diag::err_typecheck_pointer_arith_void_type
: diag::ext_gnu_void_ptr)
<< 1 /* two pointers */ << LHS->getSourceRange() << RHS->getSourceRange();
}
/// \brief Diagnose invalid arithmetic on a void pointer.
static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
S.Diag(Loc, S.getLangOptions().CPlusPlus
? diag::err_typecheck_pointer_arith_void_type
: diag::ext_gnu_void_ptr)
<< 0 /* one pointer */ << Pointer->getSourceRange();
}
/// \brief Diagnose invalid arithmetic on two function pointers.
static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
assert(LHS->getType()->isAnyPointerType());
assert(RHS->getType()->isAnyPointerType());
S.Diag(Loc, S.getLangOptions().CPlusPlus
? diag::err_typecheck_pointer_arith_function_type
: diag::ext_gnu_ptr_func_arith)
<< 1 /* two pointers */ << LHS->getType()->getPointeeType()
// We only show the second type if it differs from the first.
<< (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(),
RHS->getType())
<< RHS->getType()->getPointeeType()
<< LHS->getSourceRange() << RHS->getSourceRange();
}
/// \brief Diagnose invalid arithmetic on a function pointer.
static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
assert(Pointer->getType()->isAnyPointerType());
S.Diag(Loc, S.getLangOptions().CPlusPlus
? diag::err_typecheck_pointer_arith_function_type
: diag::ext_gnu_ptr_func_arith)
<< 0 /* one pointer */ << Pointer->getType()->getPointeeType()
<< 0 /* one pointer, so only one type */
<< Pointer->getSourceRange();
}
/// \brief Check the validity of an arithmetic pointer operand.
///
/// If the operand has pointer type, this code will check for pointer types
/// which are invalid in arithmetic operations. These will be diagnosed
/// appropriately, including whether or not the use is supported as an
/// extension.
///
/// \returns True when the operand is valid to use (even if as an extension).
static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
Expr *Operand) {
if (!Operand->getType()->isAnyPointerType()) return true;
QualType PointeeTy = Operand->getType()->getPointeeType();
if (PointeeTy->isVoidType()) {
diagnoseArithmeticOnVoidPointer(S, Loc, Operand);
return !S.getLangOptions().CPlusPlus;
}
if (PointeeTy->isFunctionType()) {
diagnoseArithmeticOnFunctionPointer(S, Loc, Operand);
return !S.getLangOptions().CPlusPlus;
}
if ((Operand->getType()->isPointerType() &&
!Operand->getType()->isDependentType()) ||
Operand->getType()->isObjCObjectPointerType()) {
QualType PointeeTy = Operand->getType()->getPointeeType();
if (S.RequireCompleteType(
Loc, PointeeTy,
S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
<< PointeeTy << Operand->getSourceRange()))
return false;
}
return true;
}
/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer
/// operands.
///
/// This routine will diagnose any invalid arithmetic on pointer operands much
/// like \see checkArithmeticOpPointerOperand. However, it has special logic
/// for emitting a single diagnostic even for operations where both LHS and RHS
/// are (potentially problematic) pointers.
///
/// \returns True when the operand is valid to use (even if as an extension).
static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
bool isLHSPointer = LHS->getType()->isAnyPointerType();
bool isRHSPointer = RHS->getType()->isAnyPointerType();
if (!isLHSPointer && !isRHSPointer) return true;
QualType LHSPointeeTy, RHSPointeeTy;
if (isLHSPointer) LHSPointeeTy = LHS->getType()->getPointeeType();
if (isRHSPointer) RHSPointeeTy = RHS->getType()->getPointeeType();
// Check for arithmetic on pointers to incomplete types.
bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType();
bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType();
if (isLHSVoidPtr || isRHSVoidPtr) {
if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHS);
else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHS);
else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHS, RHS);
return !S.getLangOptions().CPlusPlus;
}
bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType();
bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType();
if (isLHSFuncPtr || isRHSFuncPtr) {
if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHS);
else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, RHS);
else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHS, RHS);
return !S.getLangOptions().CPlusPlus;
}
Expr *Operands[] = { LHS, RHS };
for (unsigned i = 0; i < 2; ++i) {
Expr *Operand = Operands[i];
if ((Operand->getType()->isPointerType() &&
!Operand->getType()->isDependentType()) ||
Operand->getType()->isObjCObjectPointerType()) {
QualType PointeeTy = Operand->getType()->getPointeeType();
if (S.RequireCompleteType(
Loc, PointeeTy,
S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
<< PointeeTy << Operand->getSourceRange()))
return false;
}
}
return true;
}
QualType Sema::CheckAdditionOperands( // C99 6.5.6 QualType Sema::CheckAdditionOperands( // C99 6.5.6
ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) {
if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) {
@ -5620,42 +5760,12 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
std::swap(PExp, IExp); std::swap(PExp, IExp);
if (PExp->getType()->isAnyPointerType()) { if (PExp->getType()->isAnyPointerType()) {
if (IExp->getType()->isIntegerType()) { if (IExp->getType()->isIntegerType()) {
if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
return QualType();
QualType PointeeTy = PExp->getType()->getPointeeType(); QualType PointeeTy = PExp->getType()->getPointeeType();
// Check for arithmetic on pointers to incomplete types.
if (PointeeTy->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
// GNU extension: arithmetic on pointer to void
Diag(Loc, diag::ext_gnu_void_ptr)
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
} else if (PointeeTy->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
<< PExp->getType() << PExp->getSourceRange();
return QualType();
}
// GNU extension: arithmetic on pointer to function
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< PExp->getType() << PExp->getSourceRange();
} else {
// Check if we require a complete type.
if (((PExp->getType()->isPointerType() &&
!PExp->getType()->isDependentType()) ||
PExp->getType()->isObjCObjectPointerType()) &&
RequireCompleteType(Loc, PointeeTy,
PDiag(diag::err_typecheck_arithmetic_incomplete_type)
<< PExp->getSourceRange()
<< PExp->getType()))
return QualType();
}
// Diagnose bad cases where we step over interface counts. // Diagnose bad cases where we step over interface counts.
if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { if (PointeeTy->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface) Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@ -5705,35 +5815,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (lex.get()->getType()->isAnyPointerType()) { if (lex.get()->getType()->isAnyPointerType()) {
QualType lpointee = lex.get()->getType()->getPointeeType(); QualType lpointee = lex.get()->getType()->getPointeeType();
// The LHS must be an completely-defined object type.
bool ComplainAboutVoid = false;
Expr *ComplainAboutFunc = 0;
if (lpointee->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
// GNU C extension: arithmetic on pointer to void
ComplainAboutVoid = true;
} else if (lpointee->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
<< lex.get()->getType() << lex.get()->getSourceRange();
return QualType();
}
// GNU C extension: arithmetic on pointer to function
ComplainAboutFunc = lex.get();
} else if (!lpointee->isDependentType() &&
RequireCompleteType(Loc, lpointee,
PDiag(diag::err_typecheck_sub_ptr_object)
<< lex.get()->getSourceRange()
<< lex.get()->getType()))
return QualType();
// Diagnose bad cases where we step over interface counts. // Diagnose bad cases where we step over interface counts.
if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) {
Diag(Loc, diag::err_arithmetic_nonfragile_interface) Diag(Loc, diag::err_arithmetic_nonfragile_interface)
@ -5743,13 +5824,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
// The result type of a pointer-int computation is the pointer type. // The result type of a pointer-int computation is the pointer type.
if (rex.get()->getType()->isIntegerType()) { if (rex.get()->getType()->isIntegerType()) {
if (ComplainAboutVoid) if (!checkArithmeticOpPointerOperand(*this, Loc, lex.get()))
Diag(Loc, diag::ext_gnu_void_ptr) return QualType();
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex.get()->getType(); if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return lex.get()->getType(); return lex.get()->getType();
@ -5759,33 +5835,6 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) { if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) {
QualType rpointee = RHSPTy->getPointeeType(); QualType rpointee = RHSPTy->getPointeeType();
// RHS must be a completely-type object type.
// Handle the GNU void* extension.
if (rpointee->isVoidType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_void_type)
<< lex.get()->getSourceRange() << rex.get()->getSourceRange();
return QualType();
}
ComplainAboutVoid = true;
} else if (rpointee->isFunctionType()) {
if (getLangOptions().CPlusPlus) {
Diag(Loc, diag::err_typecheck_pointer_arith_function_type)
<< rex.get()->getType() << rex.get()->getSourceRange();
return QualType();
}
// GNU extension: arithmetic on pointer to function
if (!ComplainAboutFunc)
ComplainAboutFunc = rex.get();
} else if (!rpointee->isDependentType() &&
RequireCompleteType(Loc, rpointee,
PDiag(diag::err_typecheck_sub_ptr_object)
<< rex.get()->getSourceRange()
<< rex.get()->getType()))
return QualType();
if (getLangOptions().CPlusPlus) { if (getLangOptions().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add] // Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
@ -5806,13 +5855,9 @@ QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex,
} }
} }
if (ComplainAboutVoid) if (!checkArithmeticBinOpPointerOperands(*this, Loc,
Diag(Loc, diag::ext_gnu_void_ptr) lex.get(), rex.get()))
<< lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType();
if (ComplainAboutFunc)
Diag(Loc, diag::ext_gnu_ptr_func_arith)
<< ComplainAboutFunc->getType()
<< ComplainAboutFunc->getSourceRange();
if (CompLHSTy) *CompLHSTy = lex.get()->getType(); if (CompLHSTy) *CompLHSTy = lex.get()->getType();
return Context.getPointerDiffType(); return Context.getPointerDiffType();
@ -6819,29 +6864,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
QualType PointeeTy = ResType->getPointeeType(); QualType PointeeTy = ResType->getPointeeType();
// C99 6.5.2.4p2, 6.5.6p2 // C99 6.5.2.4p2, 6.5.6p2
if (PointeeTy->isVoidType()) { if (!checkArithmeticOpPointerOperand(S, OpLoc, Op))
if (S.getLangOptions().CPlusPlus) {
S.Diag(OpLoc, diag::err_typecheck_pointer_arith_void_type)
<< Op->getSourceRange();
return QualType();
}
// Pointer to void is a GNU extension in C.
S.Diag(OpLoc, diag::ext_gnu_void_ptr) << Op->getSourceRange();
} else if (PointeeTy->isFunctionType()) {
if (S.getLangOptions().CPlusPlus) {
S.Diag(OpLoc, diag::err_typecheck_pointer_arith_function_type)
<< Op->getType() << Op->getSourceRange();
return QualType();
}
S.Diag(OpLoc, diag::ext_gnu_ptr_func_arith)
<< ResType << Op->getSourceRange();
} else if (S.RequireCompleteType(OpLoc, PointeeTy,
S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
<< Op->getSourceRange()
<< ResType))
return QualType(); return QualType();
// Diagnose bad cases where we step over interface counts. // Diagnose bad cases where we step over interface counts.
else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) { else if (PointeeTy->isObjCObjectType() && S.LangOpts.ObjCNonFragileABI) {
S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface) S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)

View File

@ -129,7 +129,7 @@ void g() {
void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}} void *begin(); // expected-note {{selected 'begin' function with iterator type 'void *'}}
void *end(); void *end();
}; };
for (auto u : NoIncr()) { // expected-error {{arithmetic on pointer to void type}} for (auto u : NoIncr()) { // expected-error {{arithmetic on a pointer to void type}}
} }
struct NoNotEq { struct NoNotEq {

View File

@ -7,14 +7,14 @@ struct X0 {
}; };
T* f0(T* ptr) { T* f0(T* ptr) {
return ptr + 1; // expected-error{{pointer to function}} return ptr + 1; // expected-error{{pointer to the function}}
} }
static T* static_member; static T* static_member;
}; };
template<typename T> template<typename T>
T* X0<T>::static_member = ((T*)0) + 1; // expected-error{{pointer to function}} T* X0<T>::static_member = ((T*)0) + 1; // expected-error{{pointer to the function}}
template class X0<int>; // okay template class X0<int>; // okay

View File

@ -22,7 +22,7 @@ void func() {
} }
int h[]; // expected-warning {{tentative array definition assumed to have one element}} int h[]; // expected-warning {{tentative array definition assumed to have one element}}
int (*i)[] = &h+1; // expected-error {{arithmetic on pointer to incomplete type 'int (*)[]'}} int (*i)[] = &h+1; // expected-error {{arithmetic on a pointer to an incomplete type 'int []'}}
struct bar j = {1}; // expected-error {{variable has incomplete type 'struct bar'}} \ struct bar j = {1}; // expected-error {{variable has incomplete type 'struct bar'}} \
expected-note {{forward declaration of 'struct bar'}} expected-note {{forward declaration of 'struct bar'}}

View File

@ -3,19 +3,19 @@
typedef struct S S; // expected-note 3 {{forward declaration of 'struct S'}} typedef struct S S; // expected-note 3 {{forward declaration of 'struct S'}}
void a(S* b, void* c) { void a(S* b, void* c) {
void (*fp)(int) = 0; void (*fp)(int) = 0;
b++; // expected-error {{arithmetic on pointer to incomplete type}} b++; // expected-error {{arithmetic on a pointer to an incomplete type}}
b += 1; // expected-error {{arithmetic on pointer to incomplete type}} b += 1; // expected-error {{arithmetic on a pointer to an incomplete type}}
c++; // expected-warning {{use of GNU void* extension}} c++; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
c += 1; // expected-warning {{use of GNU void* extension}} c += 1; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
c--; // expected-warning {{use of GNU void* extension}} c--; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
c -= 1; // expected-warning {{use of GNU void* extension}} c -= 1; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
(void) c[1]; // expected-warning {{use of GNU void* extension}} (void) c[1]; // expected-warning {{arithmetic on a pointer to void is a GNU extension}}
b = 1+b; // expected-error {{arithmetic on pointer to incomplete type}} b = 1+b; // expected-error {{arithmetic on a pointer to an incomplete type}}
/* The next couple tests are only pedantic warnings in gcc */ /* The next couple tests are only pedantic warnings in gcc */
void (*d)(S*,void*) = a; void (*d)(S*,void*) = a;
d += 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} d += 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
d++; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} d++; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
d--; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} d--; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
d -= 1; // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} d -= 1; // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
(void)(1 + d); // expected-warning {{arithmetic on pointer to function type 'void (*)(S *, void *)' is a GNU extension}} (void)(1 + d); // expected-warning {{arithmetic on a pointer to the function type 'void (S *, void *)' is a GNU extension}}
} }

View File

@ -7,5 +7,5 @@ int a(char* a, rchar* b) {
// <rdar://problem/6520707> // <rdar://problem/6520707>
void f0(void (*fp)(void)) { void f0(void (*fp)(void)) {
int x = fp - fp; // expected-warning{{arithmetic on pointer to function type 'void (*)(void)' is a GNU extension}} int x = fp - fp; // expected-warning{{arithmetic on pointers to the function type 'void (void)' is a GNU extension}}
} }

View File

@ -7,15 +7,15 @@ int sub1(int *a, double *b) {
} }
void *sub2(struct incomplete *P) { void *sub2(struct incomplete *P) {
return P-4; /* expected-error{{subtraction of pointer 'struct incomplete *' requires pointee to be a complete object type}} */ return P-4; /* expected-error{{arithmetic on a pointer to an incomplete type 'struct incomplete'}} */
} }
void *sub3(void *P) { void *sub3(void *P) {
return P-4; /* expected-warning{{GNU void* extension}} */ return P-4; /* expected-warning{{arithmetic on a pointer to void is a GNU extension}} */
} }
int sub4(void *P, void *Q) { int sub4(void *P, void *Q) {
return P-Q; /* expected-warning{{GNU void* extension}} */ return P-Q; /* expected-warning{{arithmetic on pointers to void is a GNU extension}} */
} }
int sub5(void *P, int *Q) { int sub5(void *P, int *Q) {

View File

@ -33,7 +33,7 @@ void f() {
v = 0 ? NULL + d : d + NULL; // \ v = 0 ? NULL + d : d + NULL; // \
expected-error {{invalid operands to binary expression ('long' and 'void (X::*)()')}} \ expected-error {{invalid operands to binary expression ('long' and 'void (X::*)()')}} \
expected-error {{invalid operands to binary expression ('void (X::*)()' and 'long')}} expected-error {{invalid operands to binary expression ('void (X::*)()' and 'long')}}
v = 0 ? NULL + e : e + NULL; // expected-error 2{{arithmetic on pointer to function type 'void (*)()'}} v = 0 ? NULL + e : e + NULL; // expected-error 2{{arithmetic on a pointer to the function type 'void ()'}}
v = 0 ? NULL + f : f + NULL; // expected-warning 2{{use of NULL in arithmetic operation}} v = 0 ? NULL + f : f + NULL; // expected-warning 2{{use of NULL in arithmetic operation}}
v = 0 ? NULL + "f" : "f" + NULL; // expected-warning 2{{use of NULL in arithmetic operation}} v = 0 ? NULL + "f" : "f" + NULL; // expected-warning 2{{use of NULL in arithmetic operation}}

View File

@ -7,7 +7,7 @@ int g0 = sizeof(I0); // expected-error{{invalid application of 'sizeof' to an in
// rdar://6821047 // rdar://6821047
void *g3(I0 *P) { void *g3(I0 *P) {
P = P+5; // expected-error {{arithmetic on pointer to incomplete type 'I0 *'}} P = P+5; // expected-error {{arithmetic on a pointer to an incomplete type 'I0'}}
return &P[4]; // expected-error{{subscript of pointer to incomplete type 'I0'}} return &P[4]; // expected-error{{subscript of pointer to incomplete type 'I0'}}
} }