diff options
Diffstat (limited to 'lib/Sema/SemaType.cpp')
-rw-r--r-- | lib/Sema/SemaType.cpp | 884 |
1 files changed, 642 insertions, 242 deletions
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 453531d98d..040e7f161d 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -70,37 +70,464 @@ static bool isOmittedBlockReturnType(const Declarator &D) { return false; } -typedef std::pair<const AttributeList*,QualType> DelayedAttribute; -typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet; - -static void ProcessTypeAttributeList(Sema &S, QualType &Type, - bool IsDeclSpec, - const AttributeList *Attrs, - DelayedAttributeSet &DelayedFnAttrs); -static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr); - -static void ProcessDelayedFnAttrs(Sema &S, QualType &Type, - DelayedAttributeSet &Attrs) { - for (DelayedAttributeSet::iterator I = Attrs.begin(), - E = Attrs.end(); I != E; ++I) - if (ProcessFnAttr(S, Type, *I->first)) { - S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) - << I->first->getName() << I->second; - // Avoid any further processing of this attribute. - I->first->setInvalid(); - } - Attrs.clear(); +// 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 + +// Function type attributes. +#define FUNCTION_TYPE_ATTRS_CASELIST \ + case AttributeList::AT_noreturn: \ + case AttributeList::AT_cdecl: \ + case AttributeList::AT_fastcall: \ + case AttributeList::AT_stdcall: \ + case AttributeList::AT_thiscall: \ + case AttributeList::AT_pascal: \ + case AttributeList::AT_regparm + +namespace { + /// An object which stores processing state for the entire + /// GetTypeForDeclarator process. + class TypeProcessingState { + Sema &sema; + + /// The declarator being processed. + Declarator &declarator; + + /// The index of the declarator chunk we're currently processing. + /// May be the total number of valid chunks, indicating the + /// DeclSpec. + unsigned chunkIndex; + + /// Whether there are non-trivial modifications to the decl spec. + bool trivial; + + /// The original set of attributes on the DeclSpec. + llvm::SmallVector<AttributeList*, 2> savedAttrs; + + /// A list of attributes to diagnose the uselessness of when the + /// processing is complete. + llvm::SmallVector<AttributeList*, 2> ignoredTypeAttrs; + + public: + TypeProcessingState(Sema &sema, Declarator &declarator) + : sema(sema), declarator(declarator), + chunkIndex(declarator.getNumTypeObjects()), + trivial(true) {} + + Sema &getSema() const { + return sema; + } + + Declarator &getDeclarator() const { + return declarator; + } + + unsigned getCurrentChunkIndex() const { + return chunkIndex; + } + + void setCurrentChunkIndex(unsigned idx) { + assert(idx <= declarator.getNumTypeObjects()); + chunkIndex = idx; + } + + AttributeList *&getCurrentAttrListRef() const { + assert(chunkIndex <= declarator.getNumTypeObjects()); + if (chunkIndex == declarator.getNumTypeObjects()) + return getMutableDeclSpec().getAttributes().getListRef(); + return declarator.getTypeObject(chunkIndex).getAttrListRef(); + } + + /// Save the current set of attributes on the DeclSpec. + void saveDeclSpecAttrs() { + // Don't try to save them multiple times. + if (!savedAttrs.empty()) return; + + DeclSpec &spec = getMutableDeclSpec(); + for (AttributeList *attr = spec.getAttributes().getList(); attr; + attr = attr->getNext()) + savedAttrs.push_back(attr); + trivial &= savedAttrs.empty(); + } + + /// Record that we had nowhere to put the given type attribute. + /// We will diagnose such attributes later. + void addIgnoredTypeAttr(AttributeList &attr) { + ignoredTypeAttrs.push_back(&attr); + } + + /// Diagnose all the ignored type attributes, given that the + /// declarator worked out to the given type. + void diagnoseIgnoredTypeAttrs(QualType type) const { + for (llvm::SmallVectorImpl<AttributeList*>::const_iterator + i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end(); + i != e; ++i) { + AttributeList &attr = **i; + getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) + << attr.getName() << type; + } + } + + ~TypeProcessingState() { + if (trivial) return; + + restoreDeclSpecAttrs(); + } + + private: + DeclSpec &getMutableDeclSpec() const { + return const_cast<DeclSpec&>(declarator.getDeclSpec()); + } + + void restoreDeclSpecAttrs() { + assert(!savedAttrs.empty()); + getMutableDeclSpec().getAttributes().set(savedAttrs[0]); + for (unsigned i = 0, e = savedAttrs.size() - 1; i != e; ++i) + savedAttrs[i]->setNext(savedAttrs[i+1]); + savedAttrs.back()->setNext(0); + } + }; + + /// Basically std::pair except that we really want to avoid an + /// implicit operator= for safety concerns. It's also a minor + /// link-time optimization for this to be a private type. + struct AttrAndList { + /// The attribute. + AttributeList &first; + + /// The head of the list the attribute is currently in. + AttributeList *&second; + + AttrAndList(AttributeList &attr, AttributeList *&head) + : first(attr), second(head) {} + }; +} + +namespace llvm { + template <> struct isPodLike<AttrAndList> { + static const bool value = true; + }; +} + +static void spliceAttrIntoList(AttributeList &attr, AttributeList *&head) { + attr.setNext(head); + head = &attr; +} + +static void spliceAttrOutOfList(AttributeList &attr, AttributeList *&head) { + if (head == &attr) { + head = attr.getNext(); + return; + } + + AttributeList *cur = head; + while (true) { + assert(cur && cur->getNext() && "ran out of attrs?"); + if (cur->getNext() == &attr) { + cur->setNext(attr.getNext()); + return; + } + cur = cur->getNext(); + } +} + +static void moveAttrFromListToList(AttributeList &attr, + AttributeList *&fromList, + AttributeList *&toList) { + spliceAttrOutOfList(attr, fromList); + spliceAttrIntoList(attr, toList); +} + +static void processTypeAttrs(TypeProcessingState &state, + QualType &type, bool isDeclSpec, + AttributeList *attrs); + +static bool handleFunctionTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type); + +static bool handleObjCGCTypeAttr(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); +} + +/// Given that an objc_gc attribute was written somewhere on a +/// declaration *other* than on the declarator itself (for which, use +/// distributeObjCPointerTypeAttrFromDeclarator), and given that it +/// didn't apply in whatever position it was written in, try to move +/// it to a more appropriate position. +static void distributeObjCPointerTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType type) { + Declarator &declarator = state.getDeclarator(); + for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i-1); + switch (chunk.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + moveAttrFromListToList(attr, state.getCurrentAttrListRef(), + chunk.getAttrListRef()); + return; + + case DeclaratorChunk::Paren: + case DeclaratorChunk::Array: + continue; + + // Don't walk through these. + case DeclaratorChunk::Reference: + case DeclaratorChunk::Function: + case DeclaratorChunk::MemberPointer: + goto error; + } + } + error: + + state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) + << attr.getName() << type; +} + +/// Distribute an objc_gc type attribute that was written on the +/// declarator. +static void +distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, + AttributeList &attr, + QualType &declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // objc_gc goes on the innermost pointer to something that's not a + // pointer. + unsigned innermost = -1U; + bool considerDeclSpec = true; + for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i); + switch (chunk.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + innermost = i; + return; + + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + case DeclaratorChunk::Paren: + case DeclaratorChunk::Array: + continue; + + case DeclaratorChunk::Function: + considerDeclSpec = false; + goto done; + } + } + done: + + // That might actually be the decl spec if we weren't blocked by + // anything in the declarator. + if (considerDeclSpec) { + if (handleObjCPointerTypeAttr(state, attr, declSpecType)) + return; + } + + // Otherwise, if we found an appropriate chunk, splice the attribute + // into it. + if (innermost != -1U) { + moveAttrFromListToList(attr, declarator.getAttrListRef(), + declarator.getTypeObject(innermost).getAttrListRef()); + return; + } + + // Otherwise, diagnose when we're done building the type. + spliceAttrOutOfList(attr, declarator.getAttrListRef()); + state.addIgnoredTypeAttr(attr); } -static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) { - for (DelayedAttributeSet::iterator I = Attrs.begin(), - E = Attrs.end(); I != E; ++I) { - S.Diag(I->first->getLoc(), diag::warn_function_attribute_wrong_type) - << I->first->getName() << I->second; - // Avoid any further processing of this attribute. - I->first->setInvalid(); +/// A function type attribute was written somewhere in a declaration +/// *other* than on the declarator itself or in the decl spec. Given +/// that it didn't apply in whatever position it was written in, try +/// to move it to a more appropriate position. +static void distributeFunctionTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType type) { + Declarator &declarator = state.getDeclarator(); + + // Try to push the attribute from the return type of a function to + // the function itself. + for (unsigned i = state.getCurrentChunkIndex(); i != 0; --i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i-1); + switch (chunk.Kind) { + case DeclaratorChunk::Function: + moveAttrFromListToList(attr, state.getCurrentAttrListRef(), + chunk.getAttrListRef()); + return; + + case DeclaratorChunk::Paren: + case DeclaratorChunk::Pointer: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Array: + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + continue; + } } - Attrs.clear(); + + state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) + << attr.getName() << type; +} + +/// Try to distribute a function type attribute to the innermost +/// function chunk or type. Returns true if the attribute was +/// distributed, false if no location was found. +static bool +distributeFunctionTypeAttrToInnermost(TypeProcessingState &state, + AttributeList &attr, + AttributeList *&attrList, + QualType &declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // Put it on the innermost function chunk, if there is one. + for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { + DeclaratorChunk &chunk = declarator.getTypeObject(i); + if (chunk.Kind != DeclaratorChunk::Function) continue; + + moveAttrFromListToList(attr, attrList, chunk.getAttrListRef()); + return true; + } + + return handleFunctionTypeAttr(state, attr, declSpecType); +} + +/// A function type attribute was written in the decl spec. Try to +/// apply it somewhere. +static void +distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, + AttributeList &attr, + QualType &declSpecType) { + state.saveDeclSpecAttrs(); + + // Try to distribute to the innermost. + if (distributeFunctionTypeAttrToInnermost(state, attr, + state.getCurrentAttrListRef(), + declSpecType)) + return; + + // If that failed, diagnose the bad attribute when the declarator is + // fully built. + state.addIgnoredTypeAttr(attr); +} + +/// A function type attribute was written on the declarator. Try to +/// apply it somewhere. +static void +distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, + AttributeList &attr, + QualType &declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // Try to distribute to the innermost. + if (distributeFunctionTypeAttrToInnermost(state, attr, + declarator.getAttrListRef(), + declSpecType)) + return; + + // If that failed, diagnose the bad attribute when the declarator is + // fully built. + spliceAttrOutOfList(attr, declarator.getAttrListRef()); + state.addIgnoredTypeAttr(attr); +} + +/// \brief Given that there are attributes written on the declarator +/// itself, try to distribute any type attributes to the appropriate +/// declarator chunk. +/// +/// These are attributes like the following: +/// int f ATTR; +/// int (f ATTR)(); +/// but not necessarily this: +/// int f() ATTR; +static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, + QualType &declSpecType) { + // Collect all the type attributes from the declarator itself. + assert(state.getDeclarator().getAttributes() && "declarator has no attrs!"); + AttributeList *attr = state.getDeclarator().getAttributes(); + AttributeList *next; + do { + next = attr->getNext(); + + switch (attr->getKind()) { + OBJC_POINTER_TYPE_ATTRS_CASELIST: + distributeObjCPointerTypeAttrFromDeclarator(state, *attr, declSpecType); + break; + + FUNCTION_TYPE_ATTRS_CASELIST: + distributeFunctionTypeAttrFromDeclarator(state, *attr, declSpecType); + break; + + default: + break; + } + } while ((attr = next)); +} + +/// Add a synthetic '()' to a block-literal declarator if it is +/// required, given the return type. +static void maybeSynthesizeBlockSignature(TypeProcessingState &state, + QualType declSpecType) { + Declarator &declarator = state.getDeclarator(); + + // First, check whether the declarator would produce a function, + // i.e. whether the innermost semantic chunk is a function. + if (declarator.isFunctionDeclarator()) { + // If so, make that declarator a prototyped declarator. + declarator.getFunctionTypeInfo().hasPrototype = true; + return; + } + + // If there are any type objects, the type as written won't + // name a function, regardless of the decl spec type. This + // is because a block signature declarator is always an + // abstract-declarator, and abstract-declarators can't just + // be parentheses chunks. Therefore we need to build a function + // chunk unless there are no type objects and the decl spec + // type is a function. + if (!declarator.getNumTypeObjects() && declSpecType->isFunctionType()) + return; + +#ifndef NDEBUG + if (declarator.getNumTypeObjects()) { + bool isOnlyParens = true; + for (unsigned i = 0, e = declarator.getNumTypeObjects(); i != e; ++i) { + if (declarator.getTypeObject(i).Kind != DeclaratorChunk::Paren) { + isOnlyParens = false; + break; + } + } + assert(!isOnlyParens && + "non-empty abstract-declarator contained only parens!"); +#endif + } + + // Otherwise, we need to fake up a function declarator. + SourceLocation loc = declarator.getSourceRange().getBegin(); + + // ...and *prepend* it to the declarator. + declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( + ParsedAttributes(), + /*proto*/ true, + /*variadic*/ false, SourceLocation(), + /*args*/ 0, 0, + /*type quals*/ 0, + /*EH*/ false, SourceLocation(), false, 0, 0, 0, + /*parens*/ loc, loc, + declarator)); + + // For consistency, make sure the state still has us as processing + // the decl spec. + assert(state.getCurrentChunkIndex() == declarator.getNumTypeObjects() - 1); + state.setCurrentChunkIndex(declarator.getNumTypeObjects()); } /// \brief Convert the specified declspec to the appropriate type @@ -108,17 +535,17 @@ static void DiagnoseDelayedFnAttrs(Sema &S, DelayedAttributeSet &Attrs) { /// \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 &TheSema, - Declarator &TheDeclarator, - DelayedAttributeSet &Delayed) { +static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. - const DeclSpec &DS = TheDeclarator.getDeclSpec(); - SourceLocation DeclLoc = TheDeclarator.getIdentifierLoc(); + + Declarator &declarator = state.getDeclarator(); + const DeclSpec &DS = declarator.getDeclSpec(); + SourceLocation DeclLoc = declarator.getIdentifierLoc(); if (DeclLoc.isInvalid()) DeclLoc = DS.getSourceRange().getBegin(); - ASTContext &Context = TheSema.Context; + ASTContext &Context = S.Context; QualType Result; switch (DS.getTypeSpecType()) { @@ -140,13 +567,13 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (DS.getTypeSpecSign() == DeclSpec::TSS_unspecified) Result = Context.WCharTy; else if (DS.getTypeSpecSign() == DeclSpec::TSS_signed) { - TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getSignedWCharType(); } else { assert(DS.getTypeSpecSign() == DeclSpec::TSS_unsigned && "Unknown TSS value"); - TheSema.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) + S.Diag(DS.getTypeSpecSignLoc(), diag::ext_invalid_sign_spec) << DS.getSpecifierName(DS.getTypeSpecType()); Result = Context.getUnsignedWCharType(); } @@ -173,7 +600,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // If this is a missing declspec in a block literal return context, then it // is inferred from the return statements inside the block. - if (isOmittedBlockReturnType(TheDeclarator)) { + if (isOmittedBlockReturnType(declarator)) { Result = Context.DependentTy; break; } @@ -185,11 +612,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. - if (TheSema.getLangOptions().ImplicitInt) { + if (S.getLangOptions().ImplicitInt) { // In C89 mode, we only warn if there is a completely missing declspec // when one is not allowed. if (DS.isEmpty()) { - TheSema.Diag(DeclLoc, diag::ext_missing_declspec) + S.Diag(DeclLoc, diag::ext_missing_declspec) << DS.getSourceRange() << FixItHint::CreateInsertion(DS.getSourceRange().getBegin(), "int"); } @@ -199,17 +626,17 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." // FIXME: Does Microsoft really have the implicit int extension in C++? - if (TheSema.getLangOptions().CPlusPlus && - !TheSema.getLangOptions().Microsoft) { - TheSema.Diag(DeclLoc, diag::err_missing_type_specifier) + if (S.getLangOptions().CPlusPlus && + !S.getLangOptions().Microsoft) { + S.Diag(DeclLoc, diag::err_missing_type_specifier) << DS.getSourceRange(); // When this occurs in C++ code, often something is very broken with the // value being declared, poison it as invalid so we don't get chains of // errors. - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } else { - TheSema.Diag(DeclLoc, diag::ext_missing_type_specifier) + S.Diag(DeclLoc, diag::ext_missing_type_specifier) << DS.getSourceRange(); } } @@ -225,9 +652,9 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = Context.LongLongTy; // long long is a C99 feature. - if (!TheSema.getLangOptions().C99 && - !TheSema.getLangOptions().CPlusPlus0x) - TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + if (!S.getLangOptions().C99 && + !S.getLangOptions().CPlusPlus0x) + S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); break; } } else { @@ -239,9 +666,9 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = Context.UnsignedLongLongTy; // long long is a C99 feature. - if (!TheSema.getLangOptions().C99 && - !TheSema.getLangOptions().CPlusPlus0x) - TheSema.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + if (!S.getLangOptions().C99 && + !S.getLangOptions().CPlusPlus0x) + S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); break; } } @@ -258,9 +685,9 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 - TheSema.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_decimal_unsupported); Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); break; case DeclSpec::TST_class: case DeclSpec::TST_enum: @@ -270,12 +697,12 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); break; } // If the type is deprecated or unavailable, diagnose it. - TheSema.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); + S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); @@ -284,23 +711,22 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Result = Context.getTypeDeclType(D); // In C++, make an ElaboratedType. - if (TheSema.getLangOptions().CPlusPlus) { + if (S.getLangOptions().CPlusPlus) { ElaboratedTypeKeyword Keyword = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); - Result = TheSema.getElaboratedType(Keyword, DS.getTypeSpecScope(), - Result); + Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result); } if (D->isInvalidDecl()) - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); break; } case DeclSpec::TST_typename: { assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "Can't handle qualifiers on typedef names yet!"); - Result = TheSema.GetTypeFromParser(DS.getRepAsType()); + Result = S.GetTypeFromParser(DS.getRepAsType()); if (Result.isNull()) - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); else if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { if (const ObjCObjectType *ObjT = Result->getAs<ObjCObjectType>()) { @@ -326,9 +752,9 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); } else { - TheSema.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) + S.Diag(DeclLoc, diag::err_invalid_protocol_qualifiers) << DS.getSourceRange(); - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } } @@ -337,12 +763,11 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, } case DeclSpec::TST_typeofType: // FIXME: Preserve type source info. - Result = TheSema.GetTypeFromParser(DS.getRepAsType()); + Result = S.GetTypeFromParser(DS.getRepAsType()); assert(!Result.isNull() && "Didn't get a type for typeof?"); if (!Result->isDependentType()) if (const TagType *TT = Result->getAs<TagType>()) - TheSema.DiagnoseUseOfDecl(TT->getDecl(), - DS.getTypeSpecTypeLoc()); + S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); // TypeQuals handled by caller. Result = Context.getTypeOfType(Result); break; @@ -350,10 +775,10 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = TheSema.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } break; } @@ -361,10 +786,10 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = TheSema.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); } break; } @@ -376,14 +801,14 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, case DeclSpec::TST_error: Result = Context.IntTy; - TheDeclarator.setInvalidType(true); + declarator.setInvalidType(true); break; } // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { - if (TheSema.getLangOptions().Freestanding) - TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); + if (S.getLangOptions().Freestanding) + S.Diag(DS.getTypeSpecComplexLoc(), diag::ext_freestanding_complex); Result = Context.getComplexType(Result); } else if (DS.isTypeAltiVecVector()) { unsigned typeSize = static_cast<unsigned>(Context.getTypeSize(Result)); @@ -398,12 +823,18 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // FIXME: Imaginary. if (DS.getTypeSpecComplex() == DeclSpec::TSC_imaginary) - TheSema.Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported); + S.Diag(DS.getTypeSpecComplexLoc(), diag::err_imaginary_not_supported); + + // Before we process any type attributes, synthesize a block literal + // function declarator if necessary. + if (declarator.getContext() == Declarator::BlockLiteralContext) + maybeSynthesizeBlockSignature(state, Result); - // See if there are any attributes on the declspec that apply to the type (as - // opposed to the decl). - if (const AttributeList *AL = DS.getAttributes().getList()) - ProcessTypeAttributeList(TheSema, Result, true, AL, Delayed); + // Apply any type attributes from the decl spec. This may cause the + // list of type attributes to be temporarily saved while the type + // attributes are pushed around. + if (AttributeList *attrs = DS.getAttributes().getList()) + processTypeAttrs(state, Result, true, attrs); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -424,14 +855,14 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, // If we have a pointer or reference, the pointee must have an object // incomplete type. if (!EltTy->isIncompleteOrObjectType()) { - TheSema.Diag(DS.getRestrictSpecLoc(), + S.Diag(DS.getRestrictSpecLoc(), diag::err_typecheck_invalid_restrict_invalid_pointee) << EltTy << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } } else { - TheSema.Diag(DS.getRestrictSpecLoc(), - diag::err_typecheck_invalid_restrict_not_pointer) + S.Diag(DS.getRestrictSpecLoc(), + diag::err_typecheck_invalid_restrict_not_pointer) << Result << DS.getSourceRange(); TypeQuals &= ~DeclSpec::TQ_restrict; // Remove the restrict qualifier. } @@ -452,7 +883,7 @@ static QualType ConvertDeclSpecToType(Sema &TheSema, "Has CVR quals but not C, V, or R?"); Loc = DS.getRestrictSpecLoc(); } - TheSema.Diag(Loc, diag::warn_typecheck_function_qualifiers) + S.Diag(Loc, diag::warn_typecheck_function_qualifiers) << Result << DS.getSourceRange(); } @@ -981,15 +1412,15 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // have a type. QualType T; TypeSourceInfo *ReturnTypeInfo = 0; - - llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec; + + TypeProcessingState state(*this, D); switch (D.getName().getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: - T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec); + T = ConvertDeclSpecToType(*this, state); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); @@ -1017,6 +1448,9 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, break; } + if (D.getAttributes()) + distributeTypeAttrsFromDeclarator(state, T); + // Check for auto functions and trailing return type and adjust the // return type accordingly. if (getLangOptions().CPlusPlus0x && D.isFunctionDeclarator()) { @@ -1091,13 +1525,13 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.getIdentifier()) Name = D.getIdentifier(); - llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk; - // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { - DeclaratorChunk &DeclType = D.getTypeObject(e-i-1); + unsigned chunkIndex = e - i - 1; + state.setCurrentChunkIndex(chunkIndex); + DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); switch (DeclType.Kind) { default: assert(0 && "Unknown decltype!"); case DeclaratorChunk::Paren: @@ -1129,6 +1563,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = BuildPointerType(T, DeclType.Loc, Name); if (DeclType.Ptr.TypeQuals) T = BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); + break; case DeclaratorChunk::Reference: { // Verify that we're not building a reference to pointer to function with @@ -1352,12 +1787,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI); } - // For GCC compatibility, we allow attributes that apply only to - // function types to be placed on a function's return type - // instead (as long as that type doesn't happen to be function - // or function-pointer itself). - ProcessDelayedFnAttrs(*this, T, FnAttrsFromPreviousChunk); - break; } case DeclaratorChunk::MemberPointer: @@ -1418,11 +1847,9 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T = Context.IntTy; } - DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); - // See if there are any attributes on this declarator chunk. - if (const AttributeList *AL = DeclType.getAttrs()) - ProcessTypeAttributeList(*this, T, false, AL, FnAttrsFromPreviousChunk); + if (AttributeList *attrs = const_cast<AttributeList*>(DeclType.getAttrs())) + processTypeAttrs(state, T, false, attrs); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { @@ -1463,6 +1890,14 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } + // Apply any undistributed attributes from the declarator. + if (!T.isNull()) + if (AttributeList *attrs = D.getAttributes()) + processTypeAttrs(state, T, false, attrs); + + // Diagnose any ignored type attributes. + if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T); + // If there's a constexpr specifier, treat it as a top-level const. if (D.getDeclSpec().isConstexprSpecified()) { T.addConst(); @@ -1528,20 +1963,6 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } - // Process any function attributes we might have delayed from the - // declaration-specifiers. - ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec); - - // If there were any type attributes applied to the decl itself, not - // the type, apply them to the result type. But don't do this for - // block-literal expressions, which are parsed wierdly. - if (D.getContext() != Declarator::BlockLiteralContext) - if (const AttributeList *Attrs = D.getAttributes()) - ProcessTypeAttributeList(*this, T, false, Attrs, - FnAttrsFromPreviousChunk); - - DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); - if (T.isNull()) return Context.getNullTypeSourceInfo(); else if (D.isInvalidType()) @@ -1923,41 +2344,53 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } -/// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the -/// specified type. The attribute contains 1 argument, weak or strong. -static void HandleObjCGCTypeAttribute(QualType &Type, - const AttributeList &Attr, Sema &S) { - if (Type.getObjCGCAttr() != Qualifiers::GCNone) { - S.Diag(Attr.getLoc(), diag::err_attribute_multiple_objc_gc); - Attr.setInvalid(); - return; +/// 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 +/// not permit the attribute. +static bool handleObjCGCTypeAttr(TypeProcessingState &state, + AttributeList &attr, + QualType &type) { + Sema &S = state.getSema(); + + // Delay if this isn't some kind of pointer. + if (!type->isPointerType() && + !type->isObjCObjectPointerType() && + !type->isBlockPointerType()) + return false; + + if (type.getObjCGCAttr() != Qualifiers::GCNone) { + S.Diag(attr.getLoc(), diag::err_attribute_multiple_objc_gc); + attr.setInvalid(); + return true; } // Check the attribute arguments. - if (!Attr.getParameterName()) { - S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_not_string) + if (!attr.getParameterName()) { + S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) << "objc_gc" << 1; - Attr.setInvalid(); - return; + attr.setInvalid(); + return true; } Qualifiers::GC GCAttr; - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; - Attr.setInvalid(); - return; + if (attr.getNumArgs() != 0) { + S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + attr.setInvalid(); + return true; } - if (Attr.getParameterName()->isStr("weak")) |