diff options
Diffstat (limited to 'lib/Sema/SemaType.cpp')
-rw-r--r-- | lib/Sema/SemaType.cpp | 848 |
1 files changed, 684 insertions, 164 deletions
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 5fd8afa6acf4..f3e73ec5a723 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -26,36 +26,11 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/DelayedDiagnostic.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; -/// \brief Perform adjustment on the parameter type of a function. -/// -/// This routine adjusts the given parameter type @p T to the actual -/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], -/// C++ [dcl.fct]p3). The adjusted parameter type is returned. -QualType Sema::adjustParameterType(QualType T) { - // C99 6.7.5.3p7: - // A declaration of a parameter as "array of type" shall be - // adjusted to "qualified pointer to type", where the type - // qualifiers (if any) are those specified within the [ and ] of - // the array type derivation. - if (T->isArrayType()) - return Context.getArrayDecayedType(T); - - // C99 6.7.5.3p8: - // A declaration of a parameter as "function returning type" - // shall be adjusted to "pointer to function returning type", as - // in 6.3.2.1. - if (T->isFunctionType()) - return Context.getPointerType(T); - - return T; -} - - - /// isOmittedBlockReturnType - Return true if this declarator is missing a /// return type because this is a omitted return type on a block literal. static bool isOmittedBlockReturnType(const Declarator &D) { @@ -86,6 +61,11 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, useInstantiationLoc = true; break; + case AttributeList::AT_objc_ownership: + diagID = diag::warn_objc_object_attribute_wrong_type; + useInstantiationLoc = true; + break; + default: // Assume everything else was a function attribute. diagID = diag::warn_function_attribute_wrong_type; @@ -110,7 +90,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, // objc_gc applies to Objective-C pointers or, otherwise, to the // smallest available pointer type (i.e. 'void*' in 'void**'). #define OBJC_POINTER_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_objc_gc + case AttributeList::AT_objc_gc: \ + case AttributeList::AT_objc_ownership // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ @@ -295,11 +276,15 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, static bool handleObjCGCTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type); +static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, + AttributeList &attr, QualType &type); + static bool handleObjCPointerTypeAttr(TypeProcessingState &state, AttributeList &attr, QualType &type) { - // Right now, we have exactly one of these attributes: objc_gc. - assert(attr.getKind() == AttributeList::AT_objc_gc); - return handleObjCGCTypeAttr(state, attr, type); + if (attr.getKind() == AttributeList::AT_objc_gc) + return handleObjCGCTypeAttr(state, attr, type); + assert(attr.getKind() == AttributeList::AT_objc_ownership); + return handleObjCOwnershipTypeAttr(state, attr, type); } /// Given that an objc_gc attribute was written somewhere on a @@ -447,7 +432,12 @@ distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, return true; } - return handleFunctionTypeAttr(state, attr, declSpecType); + if (handleFunctionTypeAttr(state, attr, declSpecType)) { + spliceAttrOutOfList(attr, attrList); + return true; + } + + return false; } /// A function type attribute was written in the decl spec. Try to @@ -512,6 +502,11 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType); break; + case AttributeList::AT_ns_returns_retained: + if (!state.getSema().getLangOptions().ObjCAutoRefCount) + break; + // fallthrough + FUNCTION_TYPE_ATTRS_CASELIST: distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType); break; @@ -560,6 +555,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*args*/ 0, 0, /*type quals*/ 0, /*ref-qualifier*/true, SourceLocation(), + /*mutable qualifier*/SourceLocation(), /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, /*parens*/ loc, loc, declarator)); @@ -575,10 +571,11 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. -static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { +static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. + Sema &S = state.getSema(); Declarator &declarator = state.getDeclarator(); const DeclSpec &DS = declarator.getDeclSpec(); SourceLocation DeclLoc = declarator.getIdentifierLoc(); @@ -1017,6 +1014,51 @@ QualType Sema::BuildParenType(QualType T) { return Context.getParenType(T); } +/// Given that we're building a pointer or reference to the given +static QualType inferARCLifetimeForPointee(Sema &S, QualType type, + SourceLocation loc, + bool isReference) { + // Bail out if retention is unrequired or already specified. + if (!type->isObjCLifetimeType() || + type.getObjCLifetime() != Qualifiers::OCL_None) + return type; + + Qualifiers::ObjCLifetime implicitLifetime = Qualifiers::OCL_None; + + // If the object type is const-qualified, we can safely use + // __unsafe_unretained. This is safe (because there are no read + // barriers), and it'll be safe to coerce anything but __weak* to + // the resulting type. + if (type.isConstQualified()) { + implicitLifetime = Qualifiers::OCL_ExplicitNone; + + // Otherwise, check whether the static type does not require + // retaining. This currently only triggers for Class (possibly + // protocol-qualifed, and arrays thereof). + } else if (type->isObjCARCImplicitlyUnretainedType()) { + implicitLifetime = Qualifiers::OCL_ExplicitNone; + + // If that failed, give an error and recover using __autoreleasing. + } else { + // These types can show up in private ivars in system headers, so + // we need this to not be an error in those cases. Instead we + // want to delay. + if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { + S.DelayedDiagnostics.add( + sema::DelayedDiagnostic::makeForbiddenType(loc, + diag::err_arc_indirect_no_ownership, type, isReference)); + } else { + S.Diag(loc, diag::err_arc_indirect_no_ownership) << type << isReference; + } + implicitLifetime = Qualifiers::OCL_Autoreleasing; + } + assert(implicitLifetime && "didn't infer any lifetime!"); + + Qualifiers qs; + qs.addObjCLifetime(implicitLifetime); + return S.Context.getQualifiedType(type, qs); +} + /// \brief Build a pointer type. /// /// \param T The type to which we'll be building a pointer. @@ -1041,6 +1083,10 @@ QualType Sema::BuildPointerType(QualType T, assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); + // In ARC, it is forbidden to build pointers to unqualified pointers. + if (getLangOptions().ObjCAutoRefCount) + T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false); + // Build the pointer type. return Context.getPointerType(T); } @@ -1094,12 +1140,38 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return QualType(); } + // In ARC, it is forbidden to build references to unqualified pointers. + if (getLangOptions().ObjCAutoRefCount) + T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); + // Handle restrict on references. if (LValueRef) return Context.getLValueReferenceType(T, SpelledAsLValue); return Context.getRValueReferenceType(T); } +/// Check whether the specified array size makes the array type a VLA. If so, +/// return true, if not, return the size of the array in SizeVal. +static bool isArraySizeVLA(Expr *ArraySize, llvm::APSInt &SizeVal, Sema &S) { + // If the size is an ICE, it certainly isn't a VLA. + if (ArraySize->isIntegerConstantExpr(SizeVal, S.Context)) + return false; + + // If we're in a GNU mode (like gnu99, but not c99) accept any evaluatable + // value as an extension. + Expr::EvalResult Result; + if (S.LangOpts.GNUMode && ArraySize->Evaluate(Result, S.Context)) { + if (!Result.hasSideEffects() && Result.Val.isInt()) { + SizeVal = Result.Val.getInt(); + S.Diag(ArraySize->getLocStart(), diag::ext_vla_folded_to_constant); + return false; + } + } + + return true; +} + + /// \brief Build an array type. /// /// \param T The type of each element in the array. @@ -1200,11 +1272,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, T = Context.getIncompleteArrayType(T, ASM, Quals); } else if (ArraySize->isTypeDependent() || ArraySize->isValueDependent()) { T = Context.getDependentSizedArrayType(T, ArraySize, ASM, Quals, Brackets); - } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) || - (!T->isDependentType() && !T->isIncompleteType() && - !T->isConstantSizeType())) { - // Per C99, a variable array is an array with either a non-constant - // size or an element type that has a non-constant-size + } else if (!T->isDependentType() && !T->isIncompleteType() && + !T->isConstantSizeType()) { + // C99: an array with an element type that has a non-constant-size is a VLA. + T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); + } else if (isArraySizeVLA(ArraySize, ConstVal, *this)) { + // C99: an array with a non-ICE size is a VLA. We accept any expression + // that we can fold to a non-zero positive value as an extension. T = Context.getVariableArrayType(T, ArraySize, ASM, Quals, Brackets); } else { // C99 6.7.5.2p1: If the expression is a constant expression, it shall @@ -1242,10 +1316,12 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (!getLangOptions().C99) { if (T->isVariableArrayType()) { // Prohibit the use of non-POD types in VLAs. + QualType BaseT = Context.getBaseElementType(T); if (!T->isDependentType() && - !Context.getBaseElementType(T)->isPODType()) { + !BaseT.isPODType(Context) && + !BaseT->isObjCLifetimeType()) { Diag(Loc, diag::err_vla_non_pod) - << Context.getBaseElementType(T); + << BaseT; return QualType(); } // Prohibit the use of VLAs during template argument deduction. @@ -1296,8 +1372,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } - if (!T->isDependentType()) - return Context.getExtVectorType(T, vectorSize); + return Context.getExtVectorType(T, vectorSize); } return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc); @@ -1347,7 +1422,7 @@ QualType Sema::BuildFunctionType(QualType T, bool Invalid = false; for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) { - QualType ParamType = adjustParameterType(ParamTypes[Idx]); + QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; @@ -1467,6 +1542,109 @@ QualType Sema::GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo) { return QT; } +static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, + Qualifiers::ObjCLifetime ownership, + unsigned chunkIndex); + +/// Given that this is the declaration of a parameter under ARC, +/// attempt to infer attributes and such for pointer-to-whatever +/// types. +static void inferARCWriteback(TypeProcessingState &state, + QualType &declSpecType) { + Sema &S = state.getSema(); + Declarator &declarator = state.getDeclarator(); + + // TODO: should we care about decl qualifiers? + + // Check whether the declarator has the expected form. We walk + // from the inside out in order to make the block logic work. + unsigned outermostPointerIndex = 0; + bool isBlockPointer = false; + unsigned numPointers = 0; + for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { + unsigned chunkIndex = i; + DeclaratorChunk &chunk = declarator.getTypeObject(chunkIndex); + switch (chunk.Kind) { + case DeclaratorChunk::Paren: + // Ignore parens. + break; + + case DeclaratorChunk::Reference: + case DeclaratorChunk::Pointer: + // Count the number of pointers. Treat references + // interchangeably as pointers; if they're mis-ordered, normal + // type building will discover that. + outermostPointerIndex = chunkIndex; + numPointers++; + break; + + case DeclaratorChunk::BlockPointer: + // If we have a pointer to block pointer, that's an acceptable + // indirect reference; anything else is not an application of + // the rules. + if (numPointers != 1) return; + numPointers++; + outermostPointerIndex = chunkIndex; + isBlockPointer = true; + + // We don't care about pointer structure in return values here. + goto done; + + case DeclaratorChunk::Array: // suppress if written (id[])? + case DeclaratorChunk::Function: + case DeclaratorChunk::MemberPointer: + return; + } + } + done: + + // If we have *one* pointer, then we want to throw the qualifier on + // the declaration-specifiers, which means that it needs to be a + // retainable object type. + if (numPointers == 1) { + // If it's not a retainable object type, the rule doesn't apply. + if (!declSpecType->isObjCRetainableType()) return; + + // If it already has lifetime, don't do anything. + if (declSpecType.getObjCLifetime()) return; + + // Otherwise, modify the type in-place. + Qualifiers qs; + + if (declSpecType->isObjCARCImplicitlyUnretainedType()) + qs.addObjCLifetime(Qualifiers::OCL_ExplicitNone); + else + qs.addObjCLifetime(Qualifiers::OCL_Autoreleasing); + declSpecType = S.Context.getQualifiedType(declSpecType, qs); + + // If we have *two* pointers, then we want to throw the qualifier on + // the outermost pointer. + } else if (numPointers == 2) { + // If we don't have a block pointer, we need to check whether the + // declaration-specifiers gave us something that will turn into a + // retainable object pointer after we slap the first pointer on it. + if (!isBlockPointer && !declSpecType->isObjCObjectType()) + return; + + // Look for an explicit lifetime attribute there. + DeclaratorChunk &chunk = declarator.getTypeObject(outermostPointerIndex); + if (chunk.Kind != DeclaratorChunk::Pointer && + chunk.Kind != DeclaratorChunk::BlockPointer) + return; + for (const AttributeList *attr = chunk.getAttrs(); attr; + attr = attr->getNext()) + if (attr->getKind() == AttributeList::AT_objc_ownership) + return; + + transferARCOwnershipToDeclaratorChunk(state, Qualifiers::OCL_Autoreleasing, + outermostPointerIndex); + + // Any other number of pointers/references does not trigger the rule. + } else return; + + // TODO: mark whether we did this inference? +} + static void DiagnoseIgnoredQualifiers(unsigned Quals, SourceLocation ConstQualLoc, SourceLocation VolatileQualLoc, @@ -1513,47 +1691,28 @@ static void DiagnoseIgnoredQualifiers(unsigned Quals, << QualStr << NumQuals << ConstFixIt << VolatileFixIt << RestrictFixIt; } -/// GetTypeForDeclarator - Convert the type for the specified -/// declarator to Type instances. -/// -/// If OwnedDecl is non-NULL, and this declarator's decl-specifier-seq -/// owns the declaration of a type (e.g., the definition of a struct -/// type), then *OwnedDecl will receive the owned declaration. -/// -/// The result of this call will never be null, but the associated -/// type may be a null type if there's an unrecoverable error. -TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, - TagDecl **OwnedDecl, - bool AutoAllowedInTypeName) { - // Determine the type of the declarator. Not all forms of declarator - // have a type. +static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, + TypeSourceInfo *&ReturnTypeInfo) { + Sema &SemaRef = state.getSema(); + Declarator &D = state.getDeclarator(); QualType T; - TypeSourceInfo *ReturnTypeInfo = 0; - - TypeProcessingState state(*this, D); + ReturnTypeInfo = 0; - // In C++0x, deallocation functions (normal and array operator delete) - // are implicitly noexcept. - bool ImplicitlyNoexcept = false; + // The TagDecl owned by the DeclSpec. + TagDecl *OwnedTagDecl = 0; switch (D.getName().getKind()) { + case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_OperatorFunctionId: - if (getLangOptions().CPlusPlus0x) { - OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; - if (OO == OO_Delete || OO == OO_Array_Delete) - ImplicitlyNoexcept = true; - } - // Intentional fall-through. case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: - T = ConvertDeclSpecToType(*this, state); + T = ConvertDeclSpecToType(state); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { - TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); + OwnedTagDecl = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); // Owned declaration is embedded in declarator. - Owned->setEmbeddedInDeclarator(true); - if (OwnedDecl) *OwnedDecl = Owned; + OwnedTagDecl->setEmbeddedInDeclarator(true); } break; @@ -1562,14 +1721,14 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case UnqualifiedId::IK_DestructorName: // Constructors and destructors don't have return types. Use // "void" instead. - T = Context.VoidTy; + T = SemaRef.Context.VoidTy; break; case UnqualifiedId::IK_ConversionFunctionId: // The result type of a conversion function is the type that it // converts to. - T = GetTypeFromParser(D.getName().ConversionFunctionId, - &ReturnTypeInfo); + T = SemaRef.GetTypeFromParser(D.getName().ConversionFunctionId, + &ReturnTypeInfo); break; } @@ -1581,7 +1740,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // type (this is checked later) and we can skip this. In other languages // using auto, we need to check regardless. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && - (!getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) { + (!SemaRef.getLangOptions().CPlusPlus0x || !D.isFunctionDeclarator())) { int Error = -1; switch (D.getContext()) { @@ -1595,7 +1754,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::MemberContext: if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) break; - switch (cast<TagDecl>(CurContext)->getTagKind()) { + switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { case TTK_Enum: assert(0 && "unhandled tag kind"); break; case TTK_Struct: Error = 1; /* Struct member */ break; case TTK_Union: Error = 2; /* Union member */ break; @@ -1603,6 +1762,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } break; case Declarator::CXXCatchContext: + case Declarator::ObjCCatchContext: Error = 4; // Exception declaration break; case Declarator::TemplateParamContext: @@ -1619,13 +1779,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 9; // Type alias break; case Declarator::TypeNameContext: - if (!AutoAllowedInTypeName) - Error = 11; // Generic + Error = 11; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: case Declarator::ForContext: case Declarator::ConditionContext: + case Declarator::CXXNewContext: break; } @@ -1640,7 +1800,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // contains a trailing return type. That is only legal at the outermost // level. Check all declarator chunks (outermost first) anyway, to give // better diagnostics. - if (getLangOptions().CPlusPlus0x && Error != -1) { + if (SemaRef.getLangOptions().CPlusPlus0x && Error != -1) { for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); @@ -1656,15 +1816,86 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } if (Error != -1) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_not_allowed) + SemaRef.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + diag::err_auto_not_allowed) << Error; - T = Context.IntTy; + T = SemaRef.Context.IntTy; D.setInvalidType(true); } } - - if (T.isNull()) - return Context.getNullTypeSourceInfo(); + + if (SemaRef.getLangOptions().CPlusPlus && + OwnedTagDecl && OwnedTagDecl->isDefinition()) { + // Check the contexts where C++ forbids the declaration of a new class + // or enumeration in a type-specifier-seq. + switch (D.getContext()) { + case Declarator::FileContext: + case Declarator::MemberContext: + case Declarator::BlockContext: + case Declarator::ForContext: + case Declarator::BlockLiteralContext: + // C++0x [dcl.type]p3: + // A type-specifier-seq shall not define a class or enumeration unless + // it appears in the type-id of an alias-declaration (7.1.3) that is not + // the declaration of a template-declaration. + case Declarator::AliasDeclContext: + break; + case Declarator::AliasTemplateContext: + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_alias_template) + << SemaRef.Context.getTypeDeclType(OwnedTagDecl); + break; + case Declarator::TypeNameContext: + case Declarator::TemplateParamContext: + case Declarator::CXXNewContext: + case Declarator::CXXCatchContext: + case Declarator::ObjCCatchContext: + case Declarator::TemplateTypeArgContext: + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_type_specifier) + << SemaRef.Context.getTypeDeclType(OwnedTagDecl); + break; + case Declarator::PrototypeContext: + case Declarator::ObjCPrototypeContext: + case Declarator::KNRTypeListContext: + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_param_type) + << SemaRef.Context.getTypeDeclType(OwnedTagDecl); + break; + case Declarator::ConditionContext: + // C++ 6.4p2: + // The type-specifier-seq shall not contain typedef and shall not declare + // a new class or enumeration. + SemaRef.Diag(OwnedTagDecl->getLocation(), + diag::err_type_defined_in_condition); + break; + } + } + + return T; +} + +static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, + QualType declSpecType, + TypeSourceInfo *TInfo) { + + QualType T = declSpecType; + Declarator &D = state.getDeclarator(); + Sema &S = state.getSema(); + ASTContext &Context = S.Context; + const LangOptions &LangOpts = S.getLangOptions(); + + bool ImplicitlyNoexcept = false; + if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId && + LangOpts.CPlusPlus0x) { + OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; + /// In C++0x, deallocation functions (normal and array operator delete) + /// are implicitly noexcept. + if (OO == OO_Delete || OO == OO_Array_Delete) + ImplicitlyNoexcept = true; + } // The name we're declaring, if any. DeclarationName Name; @@ -1687,56 +1918,56 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::Paren: - T = BuildParenType(T); + T = S.BuildParenType(T); break; case DeclaratorChunk::BlockPointer: // If blocks are disabled, emit an error. if (!LangOpts.Blocks) - Diag(DeclType.Loc, diag::err_blocks_disable); + S.Diag(DeclType.Loc, diag::err_blocks_disable); - T = BuildBlockPointerType(T, D.getIdentifierLoc(), Name); + T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); if (DeclType.Cls.TypeQuals) - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals); break; case DeclaratorChunk::Pointer: // Verify that we're not building a pointer to pointer to function with // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { + S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } - if (getLangOptions().ObjC1 && T->getAs<ObjCObjectType>()) { + if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) { T = Context.getObjCObjectPointerType(T); if (DeclType.Ptr.TypeQuals) - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); break; } - T = BuildPointerType(T, DeclType.Loc, Name); + T = S.BuildPointerType(T, DeclType.Loc, Name); if (DeclType.Ptr.TypeQuals) - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); break; case DeclaratorChunk::Reference: { // Verify that we're not building a reference to pointer to function with // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { + S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } - T = BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name); + T = S.BuildReferenceType(T, DeclType.Ref.LValueRef, DeclType.Loc, Name); Qualifiers Quals; if (DeclType.Ref.HasRestrict) - T = BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict); + T = S.BuildQualifiedType(T, DeclType.Loc, Qualifiers::Restrict); break; } case DeclaratorChunk::Array: { // Verify that we're not building an array of pointers to function with // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); + if (LangOpts.CPlusPlus && S.CheckDistantExceptionSpec(T)) { + S.Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); D.setInvalidType(true); // Build the type anyway. } @@ -1753,13 +1984,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // FIXME: This check isn't quite right: it allows star in prototypes // for function definitions, and disallows some edge cases detailed // in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html - Diag(DeclType.Loc, diag::err_array_star_outside_prototype); + S.Diag(DeclType.Loc, diag::err_array_star_outside_prototype); ASM = ArrayType::Normal; D.setInvalidType(true); } - T = BuildArrayType(T, ASM, ArraySize, - Qualifiers::fromCVRMask(ATI.TypeQuals), - SourceRange(DeclType.Loc, DeclType.EndLoc), Name); + T = S.BuildArrayType(T, ASM, ArraySize, + Qualifiers::fromCVRMask(ATI.TypeQuals), + SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; } case DeclaratorChunk::Function: { @@ -1775,27 +2006,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // and not, for instance, a pointer to a function. if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto && !FTI.TrailingReturnType && chunkIndex == 0) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_auto_missing_trailing_return); T = Context.IntTy; D.setInvalidType(true); } else if (FTI.TrailingReturnType) { // T must be exactly 'auto' at this point. See CWG issue 681. if (isa<ParenType>(T)) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_in_parens) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } else if (T.hasQualifiers() || !isa<AutoType>(T)) { - Diag(D.getDeclSpec().getTypeSpecTypeLoc(), + S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); } - T = GetTypeFromParser( + T = S.GetTypeFromParser( ParsedType::getFromOpaquePtr(FTI.TrailingReturnType), - &ReturnTypeInfo); + &TInfo); } } @@ -1809,7 +2040,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (chunkIndex == 0 && D.getContext() == Declarator::BlockLiteralContext) diagID = diag::err_block_returning_array_function; - Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; + S.Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); } @@ -1818,7 +2049,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // class type in C++. if (isa<PointerType>(T) && T.getLocalCVRQualifiers() && (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) && - (!getLangOptions().CPlusPlus || !T->isDependentType())) { + (!LangOpts.CPlusPlus || !T->isDependentType())) { assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?"); DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1); assert(ReturnTypeChunk.Kind == DeclaratorChunk::Pointer); @@ -1829,43 +2060,43 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, SourceLocation::getFromRawEncoding(PTI.ConstQualLoc), SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc), SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc), - *this); + S); } else if (T.getCVRQualifiers() && D.getDeclSpec().getTypeQualifiers() && - (!getLangOptions().CPlusPlus || + (!LangOpts.CPlusPlus || (!T->isDependentType() && !T->isRecordType()))) { DiagnoseIgnoredQualifiers(D.getDeclSpec().getTypeQualifiers(), D.getDeclSpec().getConstSpecLoc(), D.getDeclSpec().getVolatileSpecLoc(), D.getDeclSpec().getRestrictSpecLoc(), - *this); + S); } - if (getLangOptions().CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) { + if (LangOpts.CPlusPlus && D.getDeclSpec().isTypeSpecOwned()) { // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. TagDecl *Tag = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); if (Tag->isDefinition()) - Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) + S.Diag(Tag->getLocation(), diag::err_type_defined_in_result_type) << Context.getTypeDeclType(Tag); } // Exception specs are not allowed in typedefs. Complain, but add it // anyway. if (IsTypedefName && FTI.getExceptionSpecType()) - Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) + S.Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) << (D.getContext() == Declarator::AliasDeclContext || D.getContext() == Declarator::AliasTemplateContext); - if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) { + if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T); } else { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" attribute. Scan // for this attribute now. - if (!FTI.NumArgs && FTI.isVariadic && !getLangOptions().CPlusPlus) { + if (!FTI.NumArgs && FTI.isVariadic && !LangOpts.CPlusPlus) { bool Overloadable = false; for (const AttributeList *Attrs = D.getAttributes(); Attrs; Attrs = Attrs->getNext()) { @@ -1876,13 +2107,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } if (!Overloadable) - Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); + S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg); } if (FTI.NumArgs && FTI.ArgInfo[0].Param == 0) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function // definition. - Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); + S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration); D.setInvalidType(true); break; } @@ -1899,13 +2130,18 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, llvm::SmallVector<QualType, 16> ArgTys; ArgTys.reserve(FTI.NumArgs); + llvm::SmallVector<bool, 16> ConsumedArguments; + ConsumedArguments.reserve(FTI.NumArgs); + bool HasAnyConsumedArguments = false; + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param); QualType ArgTy = Param->getType(); assert(!ArgTy.isNull() && "Couldn't parse type?"); // Adjust the parameter type. - assert((ArgTy == adjustParameterType(ArgTy)) && "Unadjusted type?"); + assert((ArgTy == Context.getAdjustedParameterType(ArgTy)) && + "Unadjusted type?"); // Look for 'void'. void is allowed only as a single argument to a // function with no other parameters (C99 6.7.5.3p10). We record @@ -1915,19 +2151,19 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // is an incomplete type (C99 6.2.5p19) and function decls cannot // have arguments of incomplete type. if (FTI.NumArgs != 1 || FTI.isVariadic) { - Diag(DeclType.Loc, diag::err_void_only_param); + S.Diag(DeclType.Loc, diag::err_void_only_param); ArgTy = Context.IntTy; Param->setType(ArgTy); } else if (FTI.ArgInfo[i].Ident) { // Reject, but continue to parse 'int(void abc)'. - Diag(FTI.ArgInfo[i].IdentLoc, + S.Diag(FTI.ArgInfo[i].IdentLoc, diag::err_param_with_void_type); ArgTy = Context.IntTy; Param->setType(ArgTy); } else { // Reject, but continue to parse 'float(const void)'. if (ArgTy.hasQualifiers()) - Diag(DeclType.Loc, diag::err_void_param_qualified); + S.Diag(DeclType.Loc, diag::err_void_param_qualified); // Do not add 'void' to the ArgTys list. break; @@ -1944,19 +2180,28 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } + if (LangOpts.ObjCAutoRefCount) { + bool Consumed = Param->hasAttr<NSConsumedAttr>(); + ConsumedArguments.push_back(Consumed); + HasAnyConsumedArguments |= Consumed; + } + ArgTys.push_back(ArgTy); } + if (HasAnyConsumedArguments) + EPI.ConsumedArguments = ConsumedArguments.data(); + llvm::SmallVector<QualType, 4> Exceptions; EPI.ExceptionSpecType = FTI.getExceptionSpecType(); if (FTI.getExceptionSpecType() == EST_Dynamic) { Exceptions.reserve(FTI.NumExceptions); for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { // FIXME: Preserve type source info. - QualType ET = GetTypeFromParser(FTI.Exceptions[ei].Ty); + QualType ET = S.GetTypeFromParser(FTI.Exceptions[ei].Ty); // Check that the type is valid for an exception spec, and // drop it if not. - if (!CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) + if (!S.CheckSpecifiedExceptionType(ET, FTI.Exceptions[ei].Range)) Exceptions.push_back(ET); } EPI.NumExceptions = Exceptions.size(); @@ -1973,7 +2218,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (!NoexceptExpr->isValueDependent() && !NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc, /*evaluated*/false)) - Diag(ErrLoc, diag::err_noexcept_needs_constant_expression) + S.Diag(ErrLoc, diag::err_noexcept_needs_constant_expression) << NoexceptExpr->getSourceRange(); else EPI.NoexceptExpr = NoexceptExpr; @@ -1996,8 +2241,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (SS.isInvalid()) { // Avoid emitting extra errors if we already errored on the scope. D.setInvalidType(true); - } else if (isDependentScopeSpecifier(SS) || - dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS))) { + } else if (S.isDependentScopeSpecifier(SS) || + dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS))) { NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); @@ -2026,7 +2271,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } } else { - Diag(DeclType.Mem.Scope().getBeginLoc(), + S.Diag(DeclType.Mem.Scope().getBeginLoc(), diag::err_illegal_decl_mempointer_in_nonclass) << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name") << DeclType.Mem.Scope().getRange(); @@ -2034,12 +2279,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } if (!ClsType.isNull()) - T = BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); + T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); if (T.isNull()) { T = Context.IntTy; D.setInvalidType(true); } else if (DeclType.Mem.TypeQuals) { - T = BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals); + T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals); } break; } @@ -2054,7 +2299,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, processTypeAttrs(state, T, false, attrs); } - if (getLangOptions().CPlusPlus && T->isFunctionType()) { + if (LangOpts.CPlusPlus && T->isFunctionType()) { const FunctionProtoType *FnTy = T->getAs<FunctionProtoType>(); assert(FnTy && "Why oh why is there not a FunctionProtoType here?"); @@ -2071,7 +2316,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FreeFunction = (D.getContext() != Declarator::MemberContext || D.getDeclSpec().isFriendSpecified()); } else { - DeclContext *DC = computeDeclContext(D.getCXXScopeSpec()); + DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec()); FreeFunction = (DC && !DC->isRecord()); } @@ -2109,16 +2354,16 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::ext_qualified_function_type_template_arg) << Quals; } else { if (FnTy->getTypeQuals() != 0) { if (D.isFunctionDeclarator()) - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type); else - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_typedef_function_type_use) << FreeFunction; } @@ -2135,11 +2380,11 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } - Diag(Loc, diag::err_invalid_ref_qualifier_function_type) + S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type) << (FnTy->getRefQualifier() == RQ_LValue) << FixItHint::CreateRemoval(Loc); } else { - Diag(D.getIdentifierLoc(), + S.Diag(D.getIdentifierLoc(), diag::err_invalid_ref_qualifier_typedef_function_type_use) << FreeFunction << (FnTy->getRefQualifier() == RQ_LValue); @@ -2192,7 +2437,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // We represent function parameter packs as function parameters whose // type is a pack expansion. if (!T->containsUnexpandedParameterPack()) { - Diag(D.getEllipsisLoc(), + S.Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_without_parameter_packs) << T << D.getSourceRange(); D.setEllipsisLoc(SourceLocation()); @@ -2212,14 +2457,15 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // it expands those parameter packs. if (T->containsUnexpandedParameterPack()) T = Context.getPackExpansionType(T, llvm::Optional<unsigned>()); - else if (!getLangOptions().CPlusPlus0x) - Diag(D.getEllipsisLoc(), diag::ext_variadic_templates); + else if (!LangOpts.CPlusPlus0x) + S.Diag(D.getEllipsisLoc(), diag::ext_variadic_templates); break; case Declarator::FileContext: case Declarator::KNRTypeListContext: case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: + case Declarator::CXXNewContext: case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: case Declarator::MemberContext: @@ -2227,11 +2473,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::ForContext: case Declarator::ConditionContext: case Declarator::CXXCatchContext: + case Declarator::ObjCCatchContext: case Declarator::BlockLiteralContext: case Declarator::TemplateTypeArgContext: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. - Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); + S.Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); D.setEllipsisLoc(SourceLocation()); break; } @@ -2241,7 +2488,138 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, return Context.getNullTypeSourceInfo(); else if (D.isInvalidType()) return Context.getTrivialTypeSourceInfo(T); - return GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo); + + return S.GetTypeSourceInfoForDeclarator(D, T, TInfo); +} + +/// GetTypeForDeclarator - Convert the type for the specified +/// declarator to Type instances. +/// +/// The result of this call will never be null, but the associated +/// type may be a null type if there's an unrecoverable error. +TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { + // Determine the type of the declarator. Not all forms of declarator + // have a type. + + TypeProcessingState state(*this, D); + + TypeSourceInfo *ReturnTypeInfo = 0; + QualType T = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); + if (T.isNull()) + return Context.getNullTypeSourceInfo(); + + if (D.isPrototypeContext() && getLangOptions().ObjCAutoRefCount) + inferARCWriteback(state, T); + + return GetFullTypeForDeclarator(state, T, ReturnTypeInfo); +} + +static void transferARCOwnershipToDeclSpec(Sema &S, + QualType &declSpecTy, + Qualifiers::ObjCLifetime ownership) { + if (declSpecTy->isObjCRetainableType() && + declSpecTy.getObjCLifetime() == Qualifiers::OCL_None) { + Qualifiers qs; + qs.addObjCLifetime(ownership); + declSpecTy = S.Context.getQualifiedType(declSpecTy, qs); + } +} + +static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, + Qualifiers::ObjCLifetime ownership, + unsigned chunkIndex) { + Sema &S = state.getSema(); + Declarator &D = state.getDeclarator(); + + // Look for an explicit lifetime attribute. + DeclaratorChunk &chunk = D.getTypeObject(chunkIndex); + for (const AttributeList *attr = chunk.getAttrs(); attr; + attr = attr->getNext()) + if (attr->getKind() == AttributeList::AT_objc_ownership) + return; + + const char *attrStr = 0; + switch (ownership) { + case Qualifiers::OCL_None: llvm_unreachable("no ownership!"); break; + case Qualifiers::OCL_ExplicitNone: attrStr = "none"; break; + case Qualifiers::OCL_Strong: attrStr = "strong"; break; + case Qualifiers::OCL_Weak: attrStr = "weak"; break; + case Qualifiers::OCL_Autoreleasing: attrStr = "autoreleasing"; break; + } + + // If there wasn't one, add one (with an invalid source location + // so that we don't make an AttributedType for it). + AttributeList *attr = D.getAttributePool() + .create(&S.Context.Idents.get("objc_ownership"), SourceLocation(), + /*scope*/ 0, SourceLocation(), + &S.Context.Idents.get(attrStr), SourceLocation(), + /*args*/ 0, 0, + /*declspec*/ false, /*C++0x*/ false); + spliceAttrIntoList(*attr, chunk.getAttrListRef()); + + // TODO: mark whether we did this inference? +} + +static void transferARCOwnership(TypeProcessingState &state, + QualType &declSpecTy, + Qualifiers::ObjCLifetime ownership) { + Sema &S = state.getSema(); + Declarator &D = state.getDeclarator(); + + int inner = -1; + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &chunk = D.getTypeObject(i); + switch (chunk.Kind) { + case DeclaratorChunk::Paren: + // Ignore parens. + break; + + case DeclaratorChunk::Array: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Pointer: + inner = i; + break; + + case DeclaratorChunk::BlockPointer: + return transferARCOwnershipToDeclaratorChunk(state, ownership, i); + + case DeclaratorChunk::Function: + case DeclaratorChunk::MemberPointer: + return; + } + } + + if (inner == -1) + return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); + + DeclaratorChunk &chunk = D.getTypeObject(inner); + if (chunk.Kind == DeclaratorChunk::Pointer) { + if (declSpecTy->isObjCRetainableType()) + return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); + if (declSpecTy->isObjCObjectType()) + return transferARCOwnershipToDeclaratorChunk(state, ownership, inner); + } else { + assert(chunk.Kind == DeclaratorChunk::Array || + chunk.Kind == DeclaratorChunk::Reference); + return transferARCOwnershipToDeclSpec(S, declSpecTy, ownership); + } +} + +TypeSourceInfo *Sema::GetTypeForDeclaratorCast(Declarator &D, QualType FromTy) { + TypeProcessingState state(*this, D); + + TypeSourceInfo *ReturnTypeInfo = 0; + QualType declSpecTy = GetDeclSpecTypeForDeclarator(state, ReturnTypeInfo); + if (declSpecTy.isNull()) + return Context.getNullTypeSourceInfo(); + + if (getLangOptions().ObjCAutoRefCount) { + Qualifiers::ObjCLifetime ownership = Context.getInnerObjCOwnership(FromTy); + if (ownership != Qualifiers::OCL_None) + transferARCOwnership(state, declSpecTy, ownership); + } + + return GetFullTypeForDeclarator(state, declSpecTy, ReturnTypeInfo); } /// Map an AttributedType::Kind to an AttributeList::Kind. @@ -2259,6 +2637,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_neon_polyvector_type; case AttributedType::attr_objc_gc: return AttributeList::AT_objc_gc; + case AttributedType::attr_objc_ownership: + return AttributeList::AT_objc_ownership; case AttributedType::attr_noreturn: return AttributeList::AT_noreturn; case AttributedType::attr_cdecl: @@ -2489,6 +2869,9 @@ namespace { llvm_unreachable("qualified type locs not expected here!"); } + void VisitAttributedTypeLoc(AttributedTypeLoc TL) { + fillAttributedTypeLoc(TL, Chunk.getAttrs()); + } void VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::BlockPointer); TL.setCaretLoc(Chunk.Loc); @@ -2657,8 +3040,7 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // the parser. assert(D.getIdentifier() == 0 && "Type name should have no identifier!"); - TagDecl *OwnedTag = 0; - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedTag); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); QualType T = TInfo->getType(); if (D.isInvalidType()) return true; @@ -2666,26 +3048,11 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { if (getLangOptions().CPlusPlus) { // Check that there are no default arguments (C++ only). CheckExtraCXXDefaultArguments(D); - - // C++0x [dcl.type]p3: - // A type-specifier-seq shall not define a class or enumeration unless - // it appears in the type-id of an alias-declaration (7.1.3) that is not - // the declaration of a template-declaration. - if (OwnedTag && OwnedTag->isDefinition()) { - if (D.getContext() == Declarator::AliasTemplateContext) - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template) - << Context.getTypeDeclType(OwnedTag); - else if (D.getContext() != Declarator::AliasDeclContext) - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) - << Context.getTypeDeclType(OwnedTag); - } } return CreateParsedType(T, TInfo); } - - //===----------------------------------------------------------------------===// // Type Attribute Processing //===----------------------------------------------------------------------===// @@ -2744,6 +3111,99 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } +/// handleObjCOwnershipTypeAttr - Process an objc_ownership +/// attribute on the specified type. +/// +/// Returns 'true' if the attribute was handled. +static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type) { + if (!type->isObjCRetainableType() && !type->isDependentType()) + return false; + + Sema &S = state.getSema(); + + if (type.getQualifiers().getObjCLifetime()) { + S.Diag(attr.getLoc(), diag::err_attr_objc_ownership_redundant) + << type; + return true; + } + + if (!attr.getParameterName()) { + S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "objc_ownership" << 1; + attr.setInvalid(); + return true; + } + + Qualifiers::ObjCLifetime lifetime; + if (attr.getParameterName()->isStr("none")) + lifetime = Qualifiers::OCL_ExplicitNone; + else if (attr.getParameterName()->isStr("strong")) + lifetime = Qualifiers::OCL_Strong; + else if (attr.getParameterName()->isStr("weak")) + lifetime = Qualifiers::OCL_Weak; + else if (attr.getParameterName()->isStr("autoreleasing")) + lifetime = Qualifiers::OCL_Autoreleasing; + else { + S.Diag(attr.getLoc(), diag::warn_attribute_type_not_supported) + << "objc_ownership" << attr.getParameterName(); + attr.setInvalid(); + return true; + } + + // Consume lifetime attributes without further comment outside of + // ARC mode. + if (!S.getLangOptions().ObjCAutoRefCount) + return true; + + Qualifiers qs; + qs.setObjCLifetime(lifetime); + QualType origType = type; + type = S.Context.getQualifiedType(type, qs); + + // If we have a valid source location for the attribute, use an + // AttributedType instead. + if (attr.getLoc().isValid()) + type = S.Context.getAttributedType(AttributedType::attr_objc_ownership, + origType, type); + + // Forbid __weak if the runtime doesn't support it. + if (lifetime == Qualifiers::OCL_Weak && + !S.getLangOptions().ObjCRuntimeHasWeak) { + + // Actually, delay this until we know what we're parsing. + if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { + S.DelayedDiagnostics.add( + sema::DelayedDiagnostic::makeForbiddenType(attr.getLoc(), + diag::err_arc_weak_no_runtime, type, /*ignored*/ 0)); + } else { + S.Diag(attr.getLoc(), diag::err_arc_weak_no_runtime); + } + + attr.setInvalid(); + return true; + } + + // Forbid __weak for class objects marked as + // objc_arc_weak_reference_unavailable + if (lifetime == Qualifiers::OCL_Weak) { + QualType T = type; + while (const PointerType *ptr = T->getAs<PointerType>()) + T = ptr->getPointeeType(); + if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { + ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); + if (Class->isArcWeakrefUnavailable()) { + S.Diag(attr.getLoc(), diag::err_arc_unsupported_weak_class); + S.Diag(ObjT->getInterfaceDecl()->getLocation(), + diag::note_class_declared); + } + } + } + + return true; +} + /// handleObjCGCTypeAttr - Process the __attribute__((objc_gc)) type /// attribute on the specified type. Returns true to indicate that /// the attribute was handled, false to indicate that the type does @@ -2954,6 +3414,23 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } + // ns_returns_retained is not always a type attribute, but if we got + // here, we're treating it as one right now. + if (attr.getKind() == AttributeList::AT_ns_returns_retained) { + assert(S.getLangOptions().ObjCAutoRefCount && + "ns_returns_retained treated as type attribute in non-ARC"); + if (attr.getNumArgs()) return true; + + // Delay if this is not a function type. + if (!unwrapped.isFunctionType()) + return false; + + FunctionType::ExtInfo EI + = unwrapped.get()->getExtInfo().withProducesResult(true); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; + } + if (attr.getKind() == AttributeList::AT_regparm) { unsigned value; if (S.CheckRegparmAttr(attr, value)) @@ -3127,6 +3604,40 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, VectorType::GenericVector); } +/// \brief Process the OpenCL-like ext_vector_type attribute when it occurs on +/// a type. +static void HandleExtVectorTypeAttr(QualType &CurType, + const AttributeList &Attr, + Sema &S) { + Expr *sizeExpr; + + // Special case where the argument is a template id. + if (Attr.getParameterName()) { + CXXScopeSpec SS; + UnqualifiedId id; + id.setIdentifier(Attr.getParameterName(), Attr.getLoc()); + + ExprResult Size = S.ActOnIdExpression(S.getCurScope(), SS, id, false, + false); + if (Size.isInvalid()) + return; + + sizeExpr = Size.get(); + } else { + // check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + sizeExpr = Attr.getArg(0); + } + + // Create the vector type. + QualType T = S.BuildExtVectorType(CurType, sizeExpr, Attr.getLoc()); + if (!T.isNull()) + CurType = T; +} + /// HandleNeonVectorTypeAttr - The "neon_vector_type" and /// "neon_polyvector_type" attributes are used to create vector types that /// are mangled according to ARM's ABI. Otherwise, these types are identical @@ -3217,6 +3728,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case AttributeList::AT_vector_size: HandleVectorSizeAttr(type, attr, state.getSema()); break; + case AttributeList::AT_ext_vector_type: + if (state.getDeclarator().getDeclSpec().getStorageClassSpec() + != DeclSpec::SCS_typedef) + HandleExtVectorTypeAttr(type, attr, state.getSema()); + break; case AttributeList::AT_neon_vector_type: HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorType::NeonVector, "neon_vector_type"); @@ -3226,11 +3742,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, VectorType::NeonPolyVector, "neon_polyvector_type"); break; - case AttributeList::AT_opencl_image_access: HandleOpenCLImageAccessAttribute(type, attr, state.getSema()); break; + case AttributeList::AT_ns_returns_retained: + if (!state.getSema().getLangOptions().ObjCAutoRefCount) + break; + // fallthrough into the function attrs + FUNCTION_TYPE_ATTRS_CASELIST: // Never process function type attributes as part of the // declaration-specifiers. |