aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--include/clang/Basic/ObjCRuntime.h28
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp7
-rw-r--r--lib/Sema/SemaExpr.cpp130
-rw-r--r--lib/Sema/SemaExprObjC.cpp20
4 files changed, 121 insertions, 64 deletions
diff --git a/include/clang/Basic/ObjCRuntime.h b/include/clang/Basic/ObjCRuntime.h
index da3ecca0f8..b24fe7cd91 100644
--- a/include/clang/Basic/ObjCRuntime.h
+++ b/include/clang/Basic/ObjCRuntime.h
@@ -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;
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 9993f448f7..166bb9a2c0 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -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)
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,