forked from OSchip/llvm-project
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:
parent
fb39f97d4c
commit
f253834456
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue