diff options
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 439 |
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) { |