aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2012-07-31 05:14:30 +0000
committerJohn McCall <rjmccall@apple.com>2012-07-31 05:14:30 +0000
commit1503f0ddab0057e33efa21393fc0577580d6287a (patch)
treefca5d7048322a3fb50866cda51890fdda6a9573a /lib/Sema
parentb48280ba1790122cd3fa6e17c88ecd6a4571a4eb (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161028 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/SemaExpr.cpp130
-rw-r--r--lib/Sema/SemaExprObjC.cpp20
2 files changed, 88 insertions, 62 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 19259b30ec..f13408e632 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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)
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index d57329b69e..638a30f13a 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -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,