aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaType.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaType.cpp')
-rw-r--r--lib/Sema/SemaType.cpp884
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"))