summaryrefslogtreecommitdiffstats
path: root/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r--lib/Sema/SemaExprCXX.cpp439
1 files changed, 352 insertions, 87 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 2f5a890..e804fcd 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -480,23 +480,63 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) {
/// ActOnCXXThrow - Parse throw expressions.
ExprResult
-Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) {
+Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) {
+ bool IsThrownVarInScope = false;
+ if (Ex) {
+ // C++0x [class.copymove]p31:
+ // When certain criteria are met, an implementation is allowed to omit the
+ // copy/move construction of a class object [...]
+ //
+ // - in a throw-expression, when the operand is the name of a
+ // non-volatile automatic object (other than a function or catch-
+ // clause parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
+ // exception object
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens()))
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) {
+ for( ; S; S = S->getParent()) {
+ if (S->isDeclScope(Var)) {
+ IsThrownVarInScope = true;
+ break;
+ }
+
+ if (S->getFlags() &
+ (Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
+ Scope::FunctionPrototypeScope | Scope::ObjCMethodScope |
+ Scope::TryScope))
+ break;
+ }
+ }
+ }
+ }
+
+ return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope);
+}
+
+ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
+ bool IsThrownVarInScope) {
// Don't report an error if 'throw' is used in system headers.
if (!getLangOptions().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";
-
+
if (Ex && !Ex->isTypeDependent()) {
- ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex);
+ ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
if (ExRes.isInvalid())
return ExprError();
Ex = ExRes.take();
}
- return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc));
+
+ return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc,
+ IsThrownVarInScope));
}
/// CheckCXXThrowOperand - Validate the operand of a throw.
-ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
+ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E,
+ bool IsThrownVarInScope) {
// C++ [except.throw]p3:
// A throw-expression initializes a temporary object, called the exception
// object, the type of which is determined by removing any top-level
@@ -535,14 +575,28 @@ ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) {
// Initialize the exception result. This implicitly weeds out
// abstract types or types with inaccessible copy constructors.
- const VarDecl *NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
-
- // FIXME: Determine whether we can elide this copy per C++0x [class.copy]p32.
+
+ // C++0x [class.copymove]p31:
+ // When certain criteria are met, an implementation is allowed to omit the
+ // copy/move construction of a class object [...]
+ //
+ // - in a throw-expression, when the operand is the name of a
+ // non-volatile automatic object (other than a function or catch-clause
+ // parameter) whose scope does not extend beyond the end of the
+ // innermost enclosing try-block (if there is one), the copy/move
+ // operation from the operand to the exception object (15.1) can be
+ // omitted by constructing the automatic object directly into the
+ // exception object
+ const VarDecl *NRVOVariable = 0;
+ if (IsThrownVarInScope)
+ NRVOVariable = getCopyElisionCandidate(QualType(), E, false);
+
InitializedEntity Entity =
InitializedEntity::InitializeException(ThrowLoc, E->getType(),
- /*NRVO=*/false);
+ /*NRVO=*/NRVOVariable != 0);
Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable,
- QualType(), E);
+ QualType(), E,
+ IsThrownVarInScope);
if (Res.isInvalid())
return ExprError();
E = Res.take();
@@ -691,7 +745,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
ExprValueKind VK = VK_RValue;
CXXCastPath BasePath;
ExprResult CastExpr =
- CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
+ CheckCastTypes(TInfo->getTypeLoc().getBeginLoc(),
+ TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0],
Kind, VK, BasePath,
/*FunctionalStyle=*/true);
if (CastExpr.isInvalid())
@@ -827,8 +882,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0, /*OwnedDecl=*/0,
- /*AllowAuto=*/true);
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/0);
QualType AllocType = TInfo->getType();
if (D.isInvalidType())
return ExprError();
@@ -902,8 +956,16 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
- QualType ResultType = Context.getPointerType(AllocType);
+ // In ARC, infer 'retaining' for the allocated
+ if (getLangOptions().ObjCAutoRefCount &&
+ AllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+ AllocType->isObjCLifetimeType()) {
+ AllocType = Context.getLifetimeQualifiedType(AllocType,
+ AllocType->getObjCARCImplicitLifetime());
+ }
+ QualType ResultType = Context.getPointerType(AllocType);
+
// C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
// or enumeration type with a non-negative value."
if (ArraySize && !ArraySize->isTypeDependent()) {
@@ -964,6 +1026,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
+ // ARC: warn about ABI issues.
+ if (getLangOptions().ObjCAutoRefCount) {
+ QualType BaseAllocType = Context.getBaseElementType(AllocType);
+ if (BaseAllocType.hasStrongOrWeakObjCLifetime())
+ Diag(StartLoc, diag::warn_err_new_delete_object_array)
+ << 0 << BaseAllocType;
+ }
+
// Note that we do *not* convert the argument in any way. It can
// be signed, larger than size_t, whatever.
}
@@ -1078,7 +1148,17 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (OperatorDelete)
MarkDeclarationReferenced(StartLoc, OperatorDelete);
- // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
+ // C++0x [expr.new]p17:
+ // If the new expression creates an array of objects of class type,
+ // access and ambiguity control are done for the destructor.
+ if (ArraySize && Constructor) {
+ if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) {
+ MarkDeclarationReferenced(StartLoc, dtor);
+ CheckDestructorAccess(StartLoc, dtor,
+ PDiag(diag::err_access_dtor)
+ << Context.getBaseElementType(AllocType));
+ }
+ }
PlacementArgs.release();
ConstructorArgs.release();
@@ -1122,6 +1202,15 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc,
else if (unsigned AddressSpace = AllocType.getAddressSpace())
return Diag(Loc, diag::err_address_space_qualified_new)
<< AllocType.getUnqualifiedType() << AddressSpace;
+ else if (getLangOptions().ObjCAutoRefCount) {
+ if (const ArrayType *AT = Context.getAsArrayType(AllocType)) {
+ QualType BaseAllocType = Context.getBaseElementType(AT);
+ if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None &&
+ BaseAllocType->isObjCLifetimeType())
+ return Diag(Loc, diag::err_arc_new_array_without_ownership)
+ << BaseAllocType;
+ }
+ }
return false;
}
@@ -1774,8 +1863,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// delete-expression; it is not necessary to cast away the constness
// (5.2.11) of the pointer expression before it is used as the operand
// of the delete-expression. ]
- Ex = ImpCastExprToType(Ex.take(), Context.getPointerType(Context.VoidTy),
- CK_NoOp);
+ if (!Context.hasSameType(Ex.get()->getType(), Context.VoidPtrTy))
+ Ex = Owned(ImplicitCastExpr::Create(Context, Context.VoidPtrTy, CK_NoOp,
+ Ex.take(), 0, VK_RValue));
if (Pointee->isArrayType() && !ArrayForm) {
Diag(StartLoc, diag::warn_delete_array_type)
@@ -1830,6 +1920,14 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (!dtor || !dtor->isVirtual())
Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
}
+
+ } else if (getLangOptions().ObjCAutoRefCount &&
+ PointeeElem->isObjCLifetimeType() &&
+ (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong ||
+ PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) &&
+ ArrayForm) {
+ Diag(StartLoc, diag::warn_err_new_delete_object_array)
+ << 1 << PointeeElem;
}
if (!OperatorDelete) {
@@ -1988,11 +2086,12 @@ static ExprResult BuildCXXCastArgument(Sema &S,
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence &ICS,
- AssignmentAction Action, bool CStyle) {
+ AssignmentAction Action,
+ CheckedConversionKind CCK) {
switch (ICS.getKind()) {
case ImplicitConversionSequence::StandardConversion: {
ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard,
- Action, CStyle);
+ Action, CCK);
if (Res.isInvalid())
return ExprError();
From = Res.take();
@@ -2027,7 +2126,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprResult Res =
PerformImplicitConversion(From, BeforeToType,
ICS.UserDefined.Before, AA_Converting,
- CStyle);
+ CCK);
if (Res.isInvalid())
return ExprError();
From = Res.take();
@@ -2047,7 +2146,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = CastArg.take();
return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
- AA_Converting, CStyle);
+ AA_Converting, CCK);
}
case ImplicitConversionSequence::AmbiguousConversion:
@@ -2076,13 +2175,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprResult
Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence& SCS,
- AssignmentAction Action, bool CStyle) {
+ AssignmentAction Action,
+ CheckedConversionKind CCK) {
+ bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast);
+
// Overall FIXME: we are recomputing too many types here and doing far too
// much extra work. What this means is that we need to keep track of more
// information that is computed when we try the implicit conversion initially,
// so that we don't need to recompute anything here.
QualType FromType = From->getType();
-
+
if (SCS.CopyConstructor) {
// FIXME: When can ToType be a reference type?
assert(!ToType->isReferenceType());
@@ -2149,12 +2251,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
case ICK_Array_To_Pointer:
FromType = Context.getArrayDecayedType(FromType);
- From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay).take();
+ From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Function_To_Pointer:
FromType = Context.getPointerType(FromType);
- From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay).take();
+ From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
default:
@@ -2178,17 +2282,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
- From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+ From = ImpCastExprToType(From, ToType, CK_NoOp,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Integral_Promotion:
case ICK_Integral_Conversion:
- From = ImpCastExprToType(From, ToType, CK_IntegralCast).take();
+ From = ImpCastExprToType(From, ToType, CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Floating_Promotion:
case ICK_Floating_Conversion:
- From = ImpCastExprToType(From, ToType, CK_FloatingCast).take();
+ From = ImpCastExprToType(From, ToType, CK_FloatingCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Complex_Promotion:
@@ -2206,21 +2313,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
} else {
CK = CK_IntegralComplexCast;
}
- From = ImpCastExprToType(From, ToType, CK).take();
+ From = ImpCastExprToType(From, ToType, CK,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
}
case ICK_Floating_Integral:
if (ToType->isRealFloatingType())
- From = ImpCastExprToType(From, ToType, CK_IntegralToFloating).take();
+ From = ImpCastExprToType(From, ToType, CK_IntegralToFloating,
+ VK_RValue, /*BasePath=*/0, CCK).take();
else
- From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral).take();
+ From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Compatible_Conversion:
- From = ImpCastExprToType(From, ToType, CK_NoOp).take();
+ From = ImpCastExprToType(From, ToType, CK_NoOp,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
+ case ICK_Writeback_Conversion:
case ICK_Pointer_Conversion: {
if (SCS.IncompatibleObjC && Action != AA_Casting) {
// Diagnose incompatible Objective-C conversions
@@ -2234,17 +2346,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
<< From->getSourceRange();
-
+
if (From->getType()->isObjCObjectPointerType() &&
ToType->isObjCObjectPointerType())
EmitRelatedResultTypeNote(From);
- }
-
+ }
+ else if (getLangOptions().ObjCAutoRefCount &&
+ !CheckObjCARCUnavailableWeakConversion(ToType,
+ From->getType())) {
+ if (Action == AA_Initializing)
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_weak_unavailable_assign);
+ else
+ Diag(From->getSourceRange().getBegin(),
+ diag::err_arc_convesion_of_weak_unavailable)
+ << (Action == AA_Casting) << From->getType() << ToType
+ << From->getSourceRange();
+ }
+
CastKind Kind = CK_Invalid;
CXXCastPath BasePath;
if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle))
return ExprError();
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ .take();
break;
}
@@ -2255,13 +2380,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
return ExprError();
if (CheckExceptionSpecCompatibility(From, ToType))
return ExprError();
- From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take();
+ From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK)
+ .take();
break;
}
case ICK_Boolean_Conversion:
From = ImpCastExprToType(From, Context.BoolTy,
- ScalarTypeToBooleanCastKind(FromType)).take();
+ ScalarTypeToBooleanCastKind(FromType),
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Derived_To_Base: {
@@ -2276,16 +2403,18 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From = ImpCastExprToType(From, ToType.getNonReferenceType(),
CK_DerivedToBase, CastCategory(From),
- &BasePath).take();
+ &BasePath, CCK).take();
break;
}
case ICK_Vector_Conversion:
- From = ImpCastExprToType(From, ToType, CK_BitCast).take();
+ From = ImpCastExprToType(From, ToType, CK_BitCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Vector_Splat:
- From = ImpCastExprToType(From, ToType, CK_VectorSplat).take();
+ From = ImpCastExprToType(From, ToType, CK_VectorSplat,
+ VK_RValue, /*BasePath=*/0, CCK).take();
break;
case ICK_Complex_Real:
@@ -2321,27 +2450,30 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// _Complex x -> x
From = ImpCastExprToType(From, ElType,
isFloatingComplex ? CK_FloatingComplexToReal
- : CK_IntegralComplexToReal).take();
+ : CK_IntegralComplexToReal,
+ VK_RValue, /*BasePath=*/0, CCK).take();
// x -> y
if (Context.hasSameUnqualifiedType(ElType, ToType)) {
// do nothing
} else if (ToType->isRealFloatingType()) {
From = ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating).take();
+ isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating,
+ VK_RValue, /*BasePath=*/0, CCK).take();
} else {
assert(ToType->isIntegerType());
From = ImpCastExprToType(From, ToType,
- isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast).take();
+ isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
}
}
break;
case ICK_Block_Pointer_Conversion: {
- From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
- VK_RValue).take();
- break;
- }
+ From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast,
+ VK_RValue, /*BasePath=*/0, CCK).take();
+ break;
+ }
case ICK_TransparentUnionConversion: {
ExprResult FromRes = Owned(From);
@@ -2376,7 +2508,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ExprValueKind VK = ToType->isReferenceType() ?
CastCategory(From) : VK_RValue;
From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
- CK_NoOp, VK).take();
+ CK_NoOp, VK, /*BasePath=*/0, CCK).take();
if (SCS.DeprecatedStringLiteralToCharPtr &&
!getLangOptions().WritableStrings)
@@ -2553,6 +2685,23 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsObject:
return T->isObjectType();
case UTT_IsScalar:
+ // Note: semantic analysis depends on Objective-C lifetime types to be
+ // considered scalar types. However, such types do not actually behave
+ // like scalar types at run time (since they may require retain/release
+ // operations), so we report them as non-scalar.
+ if (T->isObjCLifetimeType()) {
+ switch (T.getObjCLifetime()) {
+ case Qualifiers::OCL_None:
+ case Qualifiers::OCL_ExplicitNone:
+ return true;
+
+ case Qualifiers::OCL_Strong:
+ case Qualifiers::OCL_Weak:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+ }
+ }
+
return T->isScalarType();
case UTT_IsCompound:
return T->isCompoundType();
@@ -2566,13 +2715,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
case UTT_IsVolatile:
return T.isVolatileQualified();
case UTT_IsTrivial:
- return T->isTrivialType();
+ return T.isTrivialType(Self.Context);
case UTT_IsTriviallyCopyable:
- return T->isTriviallyCopyableType();
+ return T.isTriviallyCopyableType(Self.Context);
case UTT_IsStandardLayout:
return T->isStandardLayoutType();
case UTT_IsPOD:
- return T->isPODType();
+ return T.isPODType(Self.Context);
case UTT_IsLiteral:
return T->isLiteralType();
case UTT_IsEmpty:
@@ -2605,7 +2754,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// If __is_pod (type) is true then the trait is true, else if type is
// a cv class or union type (or array thereof) with a trivial default
// constructor ([class.ctor]) then the trait is true, else it is false.
- if (T->isPODType())
+ if (T.isPODType(Self.Context))
return true;
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
@@ -2617,7 +2766,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// the trait is true, else if type is a cv class or union type
// with a trivial copy constructor ([class.copy]) then the trait
// is true, else it is false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(Self.Context) || T->isReferenceType())
return true;
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
@@ -2637,7 +2786,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
if (C.getBaseElementType(T).isConstQualified())
return false;
- if (T->isPODType())
+ if (T.isPODType(Self.Context))
return true;
if (const RecordType *RT = T->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
@@ -2649,8 +2798,14 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// type (or array thereof) with a trivial destructor
// ([class.dtor]) then the trait is true, else it is
// false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(Self.Context) || T->isReferenceType())
+ return true;
+
+ // Objective-C++ ARC: autorelease types don't require destruction.
+ if (T->isObjCLifetimeType() &&
+ T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing)
return true;
+
if (const RecordType *RT =
C.getBaseElementType(T)->getAs<RecordType>())
return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
@@ -2668,8 +2823,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
return false;
if (T->isReferenceType())
return false;
- if (T->isPODType())
- return true;
+ if (T.isPODType(Self.Context) || T->isObjCLifetimeType())
+ return true;
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialCopyAssignment())
@@ -2704,7 +2859,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// if type is a cv class or union type with copy constructors that are
// known not to throw an exception then the trait is true, else it is
// false.
- if (T->isPODType() || T->isReferenceType())
+ if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType())
return true;
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -2744,7 +2899,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT,
// true, else if type is a cv class or union type (or array
// thereof) with a default constructor that is known not to
// throw an exception then the trait is true, else it is false.
- if (T->isPODType())
+ if (T.isPODType(C) || T->isObjCLifetimeType())
return true;
if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -3089,6 +3244,20 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex,
ExprValueKind &VK,
SourceLocation Loc,
bool isIndirect) {
+ assert(!lex.get()->getType()->isPlaceholderType() &&
+ !rex.get()->getType()->isPlaceholderType() &&
+ "placeholders should have been weeded out by now");
+
+ // The LHS undergoes lvalue conversions if this is ->*.
+ if (isIndirect) {
+ lex = DefaultLvalueConversion(lex.take());
+ if (lex.isInvalid()) return QualType();
+ }
+
+ // The RHS always undergoes lvalue conversions.
+ rex = DefaultLvalueConversion(rex.take());
+ if (rex.isInvalid()) return QualType();
+
const char *OpSpelling = isIndirect ? "->*" : ".*";
// C++ 5.5p2
// The binary operator .* [p3: ->*] binds its second operand, which shall
@@ -3556,7 +3725,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex
// Extension: conditional operator involving vector types.
if (LTy->isVectorType() || RTy->isVectorType())
- return CheckVectorOperands(QuestionLoc, LHS, RHS);
+ return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false);
// -- The second and third operands have arithmetic or enumeration type;
// the usual arithmetic conversions are performed to bring them to a
@@ -3828,17 +3997,83 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (!E)
return ExprError();
- if (!Context.getLangOptions().CPlusPlus)
+ assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+
+ // If the result is a glvalue, we shouldn't bind it.
+ if (!E->isRValue())
return Owned(E);
- assert(!isa<CXXBindTemporaryExpr>(E) && "Double-bound temporary?");
+ // In ARC, calls that return a retainable type can return retained,
+ // in which case we have to insert a consuming cast.
+ if (getLangOptions().ObjCAutoRefCount &&
+ E->getType()->isObjCRetainableType()) {
+
+ bool ReturnsRetained;
+
+ // For actual calls, we compute this by examining the type of the
+ // called value.
+ if (CallExpr *Call = dyn_cast<CallExpr>(E)) {
+ Expr *Callee = Call->getCallee()->IgnoreParens();
+ QualType T = Callee->getType();
+
+ if (T == Context.BoundMemberTy) {
+ // Handle pointer-to-members.
+ if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Callee))
+ T = BinOp->getRHS()->getType();
+ else if (MemberExpr *Mem = dyn_cast<MemberExpr>(Callee))
+ T = Mem->getMemberDecl()->getType();
+ }
+
+ if (const PointerType *Ptr = T->getAs<PointerType>())
+ T = Ptr->getPointeeType();
+ else if (const BlockPointerType *Ptr = T->getAs<BlockPointerType>())
+ T = Ptr->getPointeeType();
+ else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>())
+ T = MemPtr->getPointeeType();
+
+ const FunctionType *FTy = T->getAs<FunctionType>();
+ assert(FTy && "call to value not of function type?");
+ ReturnsRetained = FTy->getExtInfo().getProducesResult();
+
+ // ActOnStmtExpr arranges things so that StmtExprs of retainable
+ // type always produce a +1 object.
+ } else if (isa<StmtExpr>(E)) {
+ ReturnsRetained = true;
+
+ // For message sends and property references, we try to find an
+ // actual method. FIXME: we should infer retention by selector in
+ // cases where we don't have an actual method.
+ } else {
+ Decl *D = 0;
+ if (ObjCMessageExpr *Send = dyn_cast<ObjCMessageExpr>(E)) {
+ D = Send->getMethodDecl();
+ } else {
+ CastExpr *CE = cast<CastExpr>(E);
+ // FIXME. What other cast kinds to check for?
+ if (CE->getCastKind() == CK_ObjCProduceObject ||
+ CE->getCastKind() == CK_LValueToRValue)
+ return MaybeBindToTemporary(CE->getSubExpr());
+ assert(CE->getCastKind() == CK_GetObjCProperty);
+ const ObjCPropertyRefExpr *PRE = CE->getSubExpr()->getObjCProperty();
+ D = (PRE->isImplicitProperty() ? PRE->getImplicitPropertyGetter() : 0);
+ }
- const RecordType *RT = E->getType()->getAs<RecordType>();
- if (!RT)
+ ReturnsRetained = (D && D->hasAttr<NSReturnsRetainedAttr>());
+ }
+
+ ExprNeedsCleanups = true;
+
+ CastKind ck = (ReturnsRetained ? CK_ObjCConsumeObject
+ : CK_ObjCReclaimReturnedObject);
+ return Owned(ImplicitCastExpr::Create(Context, E->getType(), ck, E, 0,
+ VK_RValue));
+ }
+
+ if (!getLangOptions().CPlusPlus)
return Owned(E);
- // If the result is a glvalue, we shouldn't bind it.
- if (E->Classify(Context).isGLValue())
+ const RecordType *RT = E->getType()->getAs<RecordType>();
+ if (!RT)
return Owned(E);
// That should be enough to guarantee that this type is complete.
@@ -3847,15 +4082,18 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (RD->isInvalidDecl() || RD->hasTrivialDestructor())
return Owned(E);
- CXXTemporary *Temp = CXXTemporary::Create(Context, LookupDestructor(RD));
- ExprTemporaries.push_back(Temp);
- if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) {
+ CXXDestructorDecl *Destructor = LookupDestructor(RD);
+
+ CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
+ if (Destructor) {
MarkDeclarationReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_temp)
<< E->getType());
+
+ ExprTemporaries.push_back(Temp);
+ ExprNeedsCleanups = true;
}
- // FIXME: Add the temporary to the temporaries vector.
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
@@ -3864,14 +4102,16 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
assert(ExprTemporaries.size() >= FirstTemporary);
- if (ExprTemporaries.size() == FirstTemporary)
+ assert(ExprNeedsCleanups || ExprTemporaries.size() == FirstTemporary);
+ if (!ExprNeedsCleanups)
return SubExpr;
Expr *E = ExprWithCleanups::Create(Context, SubExpr,
- &ExprTemporaries[FirstTemporary],
+ ExprTemporaries.begin() + FirstTemporary,
ExprTemporaries.size() - FirstTemporary);
ExprTemporaries.erase(ExprTemporaries.begin() + FirstTemporary,
ExprTemporaries.end());
+ ExprNeedsCleanups = false;
return E;
}
@@ -3887,9 +4127,7 @@ Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) {
Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
assert(SubStmt && "sub statement can't be null!");
- unsigned FirstTemporary = ExprEvalContexts.back().NumTemporaries;
- assert(ExprTemporaries.size() >= FirstTemporary);
- if (ExprTemporaries.size() == FirstTemporary)
+ if (!ExprNeedsCleanups)
return SubStmt;
// FIXME: In order to attach the temporaries, wrap the statement into
@@ -4047,17 +4285,35 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
QualType DestructedType = DestructedTypeInfo->getType();
SourceLocation DestructedTypeStart
= DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin();
- if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
- !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
- Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
- << ObjectType << DestructedType << Base->getSourceRange()
- << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
-
- // Recover by setting the destructed type to the object type.
- DestructedType = ObjectType;
- DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) {
+ if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+ Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+ DestructedTypeStart);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ } else if (DestructedType.getObjCLifetime() !=
+ ObjectType.getObjCLifetime()) {
+
+ if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) {
+ // Okay: just pretend that the user provided the correctly-qualified
+ // type.
+ } else {
+ Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals)
+ << ObjectType << DestructedType << Base->getSourceRange()
+ << DestructedTypeInfo->getTypeLoc().getLocalSourceRange();
+ }
+
+ // Recover by setting the destructed type to the object type.
+ DestructedType = ObjectType;
+ DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
DestructedTypeStart);
- Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+ }
}
}
@@ -4293,7 +4549,16 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// [Except in specific positions,] an lvalue that does not have
// array type is converted to the value stored in the
// designated object (and is no longer an lvalue).
- if (E->isRValue()) return Owned(E);
+ if (E->isRValue()) {
+ // In C, function designators (i.e. expressions of function type)
+ // are r-values, but we still want to do function-to-pointer decay
+ // on them. This is both technically correct and convenient for
+ // some clients.
+ if (!getLangOptions().CPlusPlus && E->getType()->isFunctionType())
+ return DefaultFunctionArrayConversion(E);
+
+ return Owned(E);
+ }
// We always want to do this on ObjC property references.
if (E->getObjectKind() == OK_ObjCProperty) {
OpenPOWER on IntegriCloud