Introduce new queries on ObjCRuntime for how to interpret subscripts

on object pointers and whether pointer arithmetic on object pointers
is supported.  Make ObjFW interpret subscripts as pseudo-objects.
Based on a patch by Jonathan Schleifer.

llvm-svn: 161028
This commit is contained in:
John McCall 2012-07-31 05:14:30 +00:00
parent fb39f97d4c
commit f253834456
4 changed files with 121 additions and 64 deletions

View File

@ -170,6 +170,34 @@ public:
llvm_unreachable("bad kind");
}
/// \brief Does this runtime allow sizeof or alignof on object types?
bool allowsSizeofAlignof() const {
return isFragile();
}
/// \brief Does this runtime allow pointer arithmetic on objects?
///
/// This covers +, -, ++, --, and (if isSubscriptPointerArithmetic()
/// yields true) [].
bool allowsPointerArithmetic() const {
switch (getKind()) {
case FragileMacOSX:
case GCC:
return true;
case MacOSX:
case iOS:
case GNUstep:
case ObjFW:
return false;
}
llvm_unreachable("bad kind");
}
/// \brief Is subscripting pointer arithmetic?
bool isSubscriptPointerArithmetic() const {
return allowsPointerArithmetic();
}
/// \brief Does this runtime provide an objc_terminate function?
///
/// This is used in handlers for exceptions during the unwind process;

View File

@ -653,8 +653,11 @@ class CGObjCGNUstep : public CGObjCGNU {
}
};
/// Class used when targeting the ObjFW runtime.
class CGObjCObjFW: public CGObjCGCC {
/// The ObjFW runtime, which closely follows the GCC runtime's
/// compiler ABI. Support here is due to Jonathan Schleifer, the
/// ObjFW maintainer.
class CGObjCObjFW : public CGObjCGCC {
/// Emit class references unconditionally as direct symbol references.
virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
const std::string &Name, bool isWeak) {
if (isWeak)

View File

@ -2902,8 +2902,9 @@ static bool CheckObjCTraitOperandConstraints(Sema &S, QualType T,
SourceLocation Loc,
SourceRange ArgRange,
UnaryExprOrTypeTrait TraitKind) {
// Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode.
if (S.LangOpts.ObjCRuntime.isNonFragile() && T->isObjCObjectType()) {
// Reject sizeof(interface) and sizeof(interface<proto>) if the
// runtime doesn't allow it.
if (!S.LangOpts.ObjCRuntime.allowsSizeofAlignof() && T->isObjCObjectType()) {
S.Diag(Loc, diag::err_sizeof_nonfragile_interface)
<< T << (TraitKind == UETT_SizeOf)
<< ArgRange;
@ -3193,6 +3194,22 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
return BuildUnaryOp(S, OpLoc, Opc, Input);
}
/// \brief Diagnose if arithmetic on the given ObjC pointer is illegal.
///
/// \return true on error
static bool checkArithmeticOnObjCPointer(Sema &S,
SourceLocation opLoc,
Expr *op) {
assert(op->getType()->isObjCObjectPointerType());
if (S.LangOpts.ObjCRuntime.allowsPointerArithmetic())
return false;
S.Diag(opLoc, diag::err_arithmetic_nonfragile_interface)
<< op->getType()->castAs<ObjCObjectPointerType>()->getPointeeType()
<< op->getSourceRange();
return true;
}
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@ -3223,7 +3240,6 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc,
return CreateBuiltinArraySubscriptExpr(Base, LLoc, Idx, RLoc);
}
ExprResult
Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
Expr *Idx, SourceLocation RLoc) {
@ -3261,13 +3277,21 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
IndexExpr = RHSExp;
ResultType = PTy->getPointeeType();
} else if (const ObjCObjectPointerType *PTy =
LHSTy->getAs<ObjCObjectPointerType>()) {
LHSTy->getAs<ObjCObjectPointerType>()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
Result = BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, 0, 0);
if (!Result.isInvalid())
return Owned(Result.take());
// Use custom logic if this should be the pseudo-object subscript
// expression.
if (!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic())
return BuildObjCSubscriptExpression(RLoc, BaseExpr, IndexExpr, 0, 0);
ResultType = PTy->getPointeeType();
if (!LangOpts.ObjCRuntime.allowsPointerArithmetic()) {
Diag(LLoc, diag::err_subscript_nonfragile_interface)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
}
} else if (const PointerType *PTy = RHSTy->getAs<PointerType>()) {
// Handle the uncommon case of "123[Ptr]".
BaseExpr = RHSExp;
@ -3279,6 +3303,11 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
BaseExpr = RHSExp;
IndexExpr = LHSExp;
ResultType = PTy->getPointeeType();
if (!LangOpts.ObjCRuntime.allowsPointerArithmetic()) {
Diag(LLoc, diag::err_subscript_nonfragile_interface)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
}
} else if (const VectorType *VTy = LHSTy->getAs<VectorType>()) {
BaseExpr = LHSExp; // vectors: V[123]
IndexExpr = RHSExp;
@ -3351,13 +3380,6 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
diag::err_subscript_incomplete_type, BaseExpr))
return ExprError();
// Diagnose bad cases where we step over interface counts.
if (ResultType->isObjCObjectType() && LangOpts.ObjCRuntime.isNonFragile()) {
Diag(LLoc, diag::err_subscript_nonfragile_interface)
<< ResultType << BaseExpr->getSourceRange();
return ExprError();
}
assert(VK == VK_RValue || LangOpts.CPlusPlus ||
!ResultType.isCForbiddenLValueType());
@ -6173,17 +6195,12 @@ static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
/// \returns True if pointer has incomplete type
static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
Expr *Operand) {
if ((Operand->getType()->isPointerType() &&
!Operand->getType()->isDependentType()) ||
Operand->getType()->isObjCObjectPointerType()) {
QualType PointeeTy = Operand->getType()->getPointeeType();
if (S.RequireCompleteType(
Loc, PointeeTy,
diag::err_typecheck_arithmetic_incomplete_type,
PointeeTy, Operand->getSourceRange()))
return true;
}
return false;
assert(Operand->getType()->isAnyPointerType() &&
!Operand->getType()->isDependentType());
QualType PointeeTy = Operand->getType()->getPointeeType();
return S.RequireCompleteType(Loc, PointeeTy,
diag::err_typecheck_arithmetic_incomplete_type,
PointeeTy, Operand->getSourceRange());
}
/// \brief Check the validity of an arithmetic pointer operand.
@ -6254,26 +6271,14 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
return !S.getLangOpts().CPlusPlus;
}
if (checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false;
if (checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false;
if (isLHSPointer && checkArithmeticIncompletePointerType(S, Loc, LHSExpr))
return false;
if (isRHSPointer && checkArithmeticIncompletePointerType(S, Loc, RHSExpr))
return false;
return true;
}
/// \brief Check bad cases where we step over interface counts.
static bool checkArithmethicPointerOnNonFragileABI(Sema &S,
SourceLocation OpLoc,
Expr *Op) {
assert(Op->getType()->isAnyPointerType());
QualType PointeeTy = Op->getType()->getPointeeType();
if (!PointeeTy->isObjCObjectType() || S.LangOpts.ObjCRuntime.isFragile())
return true;
S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
<< PointeeTy << Op->getSourceRange();
return false;
}
/// diagnoseStringPlusInt - Emit a warning when adding an integer to a string
/// literal.
static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
@ -6350,13 +6355,26 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
return compType;
}
// Put any potential pointer into PExp
Expr* PExp = LHS.get(), *IExp = RHS.get();
if (IExp->getType()->isAnyPointerType())
std::swap(PExp, IExp);
// Type-checking. Ultimately the pointer's going to be in PExp;
// note that we bias towards the LHS being the pointer.
Expr *PExp = LHS.get(), *IExp = RHS.get();
if (!PExp->getType()->isAnyPointerType())
return InvalidOperands(Loc, LHS, RHS);
bool isObjCPointer;
if (PExp->getType()->isPointerType()) {
isObjCPointer = false;
} else if (PExp->getType()->isObjCObjectPointerType()) {
isObjCPointer = true;
} else {
std::swap(PExp, IExp);
if (PExp->getType()->isPointerType()) {
isObjCPointer = false;
} else if (PExp->getType()->isObjCObjectPointerType()) {
isObjCPointer = true;
} else {
return InvalidOperands(Loc, LHS, RHS);
}
}
assert(PExp->getType()->isAnyPointerType());
if (!IExp->getType()->isIntegerType())
return InvalidOperands(Loc, LHS, RHS);
@ -6364,8 +6382,7 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6
if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
return QualType();
// Diagnose bad cases where we step over interface counts.
if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, PExp))
if (isObjCPointer && checkArithmeticOnObjCPointer(*this, Loc, PExp))
return QualType();
// Check array bounds for pointer arithemtic
@ -6414,7 +6431,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
QualType lpointee = LHS.get()->getType()->getPointeeType();
// Diagnose bad cases where we step over interface counts.
if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, LHS.get()))
if (LHS.get()->getType()->isObjCObjectPointerType() &&
checkArithmeticOnObjCPointer(*this, Loc, LHS.get()))
return QualType();
// The result type of a pointer-int computation is the pointer type.
@ -7746,14 +7764,16 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
S.Diag(OpLoc, diag::warn_increment_bool) << Op->getSourceRange();
} else if (ResType->isRealType()) {
// OK!
} else if (ResType->isAnyPointerType()) {
} else if (ResType->isPointerType()) {
// C99 6.5.2.4p2, 6.5.6p2
if (!checkArithmeticOpPointerOperand(S, OpLoc, Op))
return QualType();
// Diagnose bad cases where we step over interface counts.
else if (!checkArithmethicPointerOnNonFragileABI(S, OpLoc, Op))
return QualType();
} else if (ResType->isObjCObjectPointerType()) {
// On modern runtimes, ObjC pointer arithmetic is forbidden.
// Otherwise, we just need a complete type.
if (checkArithmeticIncompletePointerType(S, OpLoc, Op) ||
checkArithmeticOnObjCPointer(S, OpLoc, Op))
return QualType();
} else if (ResType->isAnyComplexType()) {
// C99 does not support ++/-- on complex types, we allow as an extension.
S.Diag(OpLoc, diag::ext_integer_increment_complex)

View File

@ -575,27 +575,33 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
return MaybeBindToTemporary(BoxedExpr);
}
/// Build an ObjC subscript pseudo-object expression, given that
/// that's supported by the runtime.
ExprResult Sema::BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr,
Expr *IndexExpr,
ObjCMethodDecl *getterMethod,
ObjCMethodDecl *setterMethod) {
// Subscripting is only supported in the non-fragile ABI.
if (LangOpts.ObjCRuntime.isFragile())
return ExprError();
assert(!LangOpts.ObjCRuntime.isSubscriptPointerArithmetic());
// If the expression is type-dependent, there's nothing for us to do.
assert ((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) &&
"base or index cannot have dependent type here");
// We can't get dependent types here; our callers should have
// filtered them out.
assert((!BaseExpr->isTypeDependent() && !IndexExpr->isTypeDependent()) &&
"base or index cannot have dependent type here");
// Filter out placeholders in the index. In theory, overloads could
// be preserved here, although that might not actually work correctly.
ExprResult Result = CheckPlaceholderExpr(IndexExpr);
if (Result.isInvalid())
return ExprError();
IndexExpr = Result.get();
// Perform lvalue-to-rvalue conversion.
// Perform lvalue-to-rvalue conversion on the base.
Result = DefaultLvalueConversion(BaseExpr);
if (Result.isInvalid())
return ExprError();
BaseExpr = Result.get();
// Build the pseudo-object expression.
return Owned(ObjCSubscriptRefExpr::Create(Context,
BaseExpr,
IndexExpr,