forked from OSchip/llvm-project
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:
parent
a61df3f843
commit
c933221826
|
@ -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">;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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'}}
|
||||||
|
|
|
@ -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}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
||||||
|
|
|
@ -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'}}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue