aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Type.h5
-rw-r--r--include/clang/AST/TypeLoc.h14
-rw-r--r--include/clang/Sema/AttributeList.h9
-rw-r--r--include/clang/Sema/DeclSpec.h24
-rw-r--r--include/clang/Sema/Sema.h4
-rw-r--r--lib/AST/TypeLoc.cpp7
-rw-r--r--lib/CodeGen/CGBlocks.cpp20
-rw-r--r--lib/Sema/SemaDeclAttr.cpp144
-rw-r--r--lib/Sema/SemaExpr.cpp61
-rw-r--r--lib/Sema/SemaStmt.cpp2
-rw-r--r--lib/Sema/SemaType.cpp884
-rw-r--r--lib/Sema/TreeTransform.h21
-rw-r--r--test/Sema/block-return.c2
-rw-r--r--test/Sema/stdcall-fastcall.c2
14 files changed, 856 insertions, 343 deletions
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 887fc18441..541cba4e04 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -3728,11 +3728,6 @@ inline Qualifiers::GC QualType::getObjCGCAttr() const {
if (const ArrayType *AT = dyn_cast<ArrayType>(CT))
return AT->getElementType().getObjCGCAttr();
- if (const ObjCObjectPointerType *PT = CT->getAs<ObjCObjectPointerType>())
- return PT->getPointeeType().getObjCGCAttr();
- // We most look at all pointer types, not just pointer to interface types.
- if (const PointerType *PT = CT->getAs<PointerType>())
- return PT->getPointeeType().getObjCGCAttr();
return Qualifiers::GCNone;
}
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index aecc0c4e71..81ece1799b 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -133,7 +133,18 @@ public:
/// \brief Initializes this by copying its information from another
/// TypeLoc of the same type.
void initializeFullCopy(TypeLoc Other) const {
- initializeFullCopyImpl(*this, Other);
+ assert(getType() == Other.getType());
+ size_t Size = getFullDataSize();
+ memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
+ }
+
+ /// \brief Initializes this by copying its information from another
+ /// TypeLoc of the same type. The given size must be the full data
+ /// size.
+ void initializeFullCopy(TypeLoc Other, unsigned Size) const {
+ assert(getType() == Other.getType());
+ assert(getFullDataSize() == Size);
+ memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
}
friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
@@ -148,7 +159,6 @@ public:
private:
static void initializeImpl(TypeLoc TL, SourceLocation Loc);
- static void initializeFullCopyImpl(TypeLoc TL, TypeLoc Other);
static TypeLoc getNextTypeLocImpl(TypeLoc TL);
static TypeLoc IgnoreParensImpl(TypeLoc TL);
static SourceRange getLocalSourceRangeImpl(TypeLoc TL);
diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h
index 0dab666979..c3e1aead2b 100644
--- a/include/clang/Sema/AttributeList.h
+++ b/include/clang/Sema/AttributeList.h
@@ -46,7 +46,10 @@ private:
unsigned NumArgs;
AttributeList *Next;
bool DeclspecAttribute, CXX0XAttribute;
- mutable bool Invalid; /// True if already diagnosed as invalid.
+
+ /// True if already diagnosed as invalid.
+ mutable bool Invalid;
+
AttributeList(const AttributeList &); // DO NOT IMPLEMENT
void operator=(const AttributeList &); // DO NOT IMPLEMENT
void operator delete(void *); // DO NOT IMPLEMENT
@@ -302,6 +305,10 @@ public:
void clear() { list = 0; }
AttributeList *getList() const { return list; }
+ /// Returns a reference to the attribute list. Try not to introduce
+ /// dependencies on this method, it may not be long-lived.
+ AttributeList *&getListRef() { return list; }
+
private:
AttributeList *list;
};
diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h
index 7cc5b8f7a3..b13ff71379 100644
--- a/include/clang/Sema/DeclSpec.h
+++ b/include/clang/Sema/DeclSpec.h
@@ -1002,6 +1002,7 @@ struct DeclaratorChunk {
};
union {
+ TypeInfoCommon Common;
PointerTypeInfo Ptr;
ReferenceTypeInfo Ref;
ArrayTypeInfo Arr;
@@ -1026,19 +1027,12 @@ struct DeclaratorChunk {
/// getAttrs - If there are attributes applied to this declaratorchunk, return
/// them.
const AttributeList *getAttrs() const {
- switch (Kind) {
- case Pointer: return Ptr.AttrList;
- case Reference: return Ref.AttrList;
- case MemberPointer: return Mem.AttrList;
- case Array: return Arr.AttrList;
- case Function: return Fun.AttrList;
- case BlockPointer: return Cls.AttrList;
- case Paren: return 0;
- }
- llvm_unreachable("Unknown declarator kind!");
- return 0;
+ return Common.AttrList;
}
+ AttributeList *&getAttrListRef() {
+ return Common.AttrList;
+ }
/// getPointer - Return a DeclaratorChunk for a pointer.
///
@@ -1133,6 +1127,7 @@ struct DeclaratorChunk {
I.Kind = Paren;
I.Loc = LParenLoc;
I.EndLoc = RParenLoc;
+ I.Common.AttrList = 0;
return I;
}
@@ -1337,6 +1332,11 @@ public:
SetRangeEnd(EndLoc);
}
+ /// AddInnermostTypeInfo - Add a new innermost chunk to this declarator.
+ void AddInnermostTypeInfo(const DeclaratorChunk &TI) {
+ DeclTypeInfo.insert(DeclTypeInfo.begin(), TI);
+ }
+
/// getNumTypeObjects() - Return the number of types applied to this
/// declarator.
unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); }
@@ -1428,6 +1428,8 @@ public:
const AttributeList *getAttributes() const { return AttrList; }
AttributeList *getAttributes() { return AttrList; }
+ AttributeList *&getAttrListRef() { return AttrList; }
+
/// hasAttributes - do we contain any attributes?
bool hasAttributes() const {
if (getAttributes() || getDeclSpec().hasAttributes()) return true;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 5235607468..fac590a82f 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1370,6 +1370,10 @@ public:
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL);
+ bool CheckRegparmAttr(const AttributeList &attr, unsigned &value);
+ bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC);
+ bool CheckNoReturnAttr(const AttributeList &attr);
+
void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
bool &IncompleteImpl, unsigned DiagID);
void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 1fe28560f9..6dd5543966 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -94,13 +94,6 @@ void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) {
}
}
-/// \brief Initializes a type location by copying all its data from
-/// another type location of the same type.
-void TypeLoc::initializeFullCopyImpl(TypeLoc TL, TypeLoc Other) {
- assert(TL.getType() == Other.getType() && "Must copy from same type");
- memcpy(TL.getOpaqueData(), Other.getOpaqueData(), TL.getFullDataSize());
-}
-
SourceLocation TypeLoc::getBeginLoc() const {
TypeLoc Cur = *this;
while (true) {
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 510db0b1ff..36767711b4 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -198,6 +198,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
llvm::Constant *C;
llvm::Value *V;
+ bool hasWeakBlockVariable = false;
+
{
llvm::Constant *BlockVarLayout;
// C = BuildBlockStructInitlist();
@@ -268,6 +270,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
QualType Ty = E->getType();
if (BDRE && BDRE->isByRef()) {
+ if (BDRE->getDecl()->getType().isObjCGCWeak())
+ hasWeakBlockVariable = true;
Types[i+BlockFields] =
llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
} else if (BDRE && BDRE->getDecl()->getType()->isReferenceType()) {
@@ -404,18 +408,22 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
QualType BPT = BE->getType();
V = Builder.CreateBitCast(V, ConvertType(BPT));
- // See if this is a __weak block variable and the must call objc_read_weak
- // on it.
- const FunctionType *ftype = BPT->getPointeeType()->getAs<FunctionType>();
- QualType RES = ftype->getResultType();
- if (RES.isObjCGCWeak()) {
+
+ // We must call objc_read_weak on the block literal itself if it closes
+ // on any __weak __block variables. For some reason.
+ if (hasWeakBlockVariable) {
+ const llvm::Type *OrigTy = V->getType();
+
// Must cast argument to id*
const llvm::Type *ObjectPtrTy =
ConvertType(CGM.getContext().getObjCIdType());
const llvm::Type *PtrObjectPtrTy =
llvm::PointerType::getUnqual(ObjectPtrTy);
V = Builder.CreateBitCast(V, PtrObjectPtrTy);
- V = CGM.getObjCRuntime().EmitObjCWeakRead(*this, V);
+ V = CGM.getObjCRuntime().EmitObjCWeakRead(*this, V);
+
+ // Cast back to the original type.
+ V = Builder.CreateBitCast(V, OrigTy);
}
return V;
}
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 0e8ba23ca4..f4f4348802 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -78,6 +78,13 @@ static bool isFunctionOrMethodOrBlock(const Decl *d) {
return isa<BlockDecl>(d);
}
+/// Return true if the given decl has a declarator that should have
+/// been processed by Sema::GetTypeForDeclarator.
+static bool hasDeclarator(const Decl *d) {
+ // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
+ return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefDecl>(d);
+}
+
/// hasFunctionProto - Return true if the given decl has a argument
/// information. This decl should have already passed
/// isFunctionOrMethod or isFunctionOrMethodOrBlock.
@@ -766,10 +773,28 @@ static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) {
<< Attr.getName() << 12 /* variable */;
}
-static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- /* Diagnostics (if any) was emitted by Sema::ProcessFnAttr(). */
- assert(Attr.isInvalid() == false);
- d->addAttr(::new (S.Context) NoReturnAttr(Attr.getLoc(), S.Context));
+static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ if (hasDeclarator(d)) return;
+
+ if (S.CheckNoReturnAttr(attr)) return;
+
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ d->addAttr(::new (S.Context) NoReturnAttr(attr.getLoc(), S.Context));
+}
+
+bool Sema::CheckNoReturnAttr(const AttributeList &attr) {
+ if (attr.getNumArgs() != 0) {
+ Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ attr.setInvalid();
+ return true;
+ }
+
+ return false;
}
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
@@ -2251,26 +2276,36 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
d->addAttr(::new (S.Context) GNUInlineAttr(Attr.getLoc(), S.Context));
}
-static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // Diagnostic is emitted elsewhere: here we store the (valid) Attr
+static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ if (hasDeclarator(d)) return;
+
+ // Diagnostic is emitted elsewhere: here we store the (valid) attr
// in the Decl node for syntactic reasoning, e.g., pretty-printing.
- assert(Attr.isInvalid() == false);
+ CallingConv CC;
+ if (S.CheckCallingConvAttr(attr, CC))
+ return;
- switch (Attr.getKind()) {
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << attr.getName() << 0 /*function*/;
+ return;
+ }
+
+ switch (attr.getKind()) {
case AttributeList::AT_fastcall:
- d->addAttr(::new (S.Context) FastCallAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) FastCallAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_stdcall:
- d->addAttr(::new (S.Context) StdCallAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) StdCallAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_thiscall:
- d->addAttr(::new (S.Context) ThisCallAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) ThisCallAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_cdecl:
- d->addAttr(::new (S.Context) CDeclAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) CDeclAttr(attr.getLoc(), S.Context));
return;
case AttributeList::AT_pascal:
- d->addAttr(::new (S.Context) PascalAttr(Attr.getLoc(), S.Context));
+ d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context));
return;
default:
llvm_unreachable("unexpected attribute kind");
@@ -2278,42 +2313,83 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &Attr, Sema &S) {
}
}
-static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
- // check the attribute arguments.
- if (Attr.getNumArgs() != 1) {
- S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
- return;
+bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) {
+ if (attr.isInvalid())
+ return true;
+
+ if (attr.getNumArgs() != 0) {
+ Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+ attr.setInvalid();
+ return true;
}
- if (!isFunctionOrMethod(d)) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attr.getName() << 0 /*function*/;
+ // TODO: diagnose uses of these conventions on the wrong target.
+ switch (attr.getKind()) {
+ case AttributeList::AT_cdecl: CC = CC_C; break;
+ case AttributeList::AT_fastcall: CC = CC_X86FastCall; break;
+ case AttributeList::AT_stdcall: CC = CC_X86StdCall; break;
+ case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break;
+ case AttributeList::AT_pascal: CC = CC_X86Pascal; break;
+ default: llvm_unreachable("unexpected attribute kind"); return true;
+ }
+
+ return false;
+}
+
+static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) {
+ if (hasDeclarator(d)) return;
+
+ unsigned numParams;
+ if (S.CheckRegparmAttr(attr, numParams))
+ return;
+
+ if (!isa<ObjCMethodDecl>(d)) {
+ S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << attr.getName() << 0 /*function*/;
return;
}
- Expr *NumParamsExpr = Attr.getArg(0);
+ d->addAttr(::new (S.Context) RegparmAttr(attr.getLoc(), S.Context, numParams));
+}
+
+/// Checks a regparm attribute, returning true if it is ill-formed and
+/// otherwise setting numParams to the appropriate value.
+bool Sema::CheckRegparmAttr(const AttributeList &attr, unsigned &numParams) {
+ if (attr.isInvalid())
+ return true;
+
+ if (attr.getNumArgs() != 1) {
+ Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
+ attr.setInvalid();
+ return true;
+ }
+
+ Expr *NumParamsExpr = attr.getArg(0);
llvm::APSInt NumParams(32);
if (NumParamsExpr->isTypeDependent() || NumParamsExpr->isValueDependent() ||
- !NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
- S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+ !NumParamsExpr->isIntegerConstantExpr(NumParams, Context)) {
+ Diag(attr.getLoc(), diag::err_attribute_argument_not_int)
<< "regparm" << NumParamsExpr->getSourceRange();
- return;
+ attr.setInvalid();
+ return true;
}
- if (S.Context.Target.getRegParmMax() == 0) {
- S.Diag(Attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
+ if (Context.Target.getRegParmMax() == 0) {
+ Diag(attr.getLoc(), diag::err_attribute_regparm_wrong_platform)
<< NumParamsExpr->getSourceRange();
- return;
+ attr.setInvalid();
+ return true;
}
- if (NumParams.getLimitedValue(255) > S.Context.Target.getRegParmMax()) {
- S.Diag(Attr.getLoc(), diag::err_attribute_regparm_invalid_number)
- << S.Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
- return;
+ numParams = NumParams.getZExtValue();
+ if (numParams > Context.Target.getRegParmMax()) {
+ Diag(attr.getLoc(), diag::err_attribute_regparm_invalid_number)
+ << Context.Target.getRegParmMax() << NumParamsExpr->getSourceRange();
+ attr.setInvalid();
+ return true;
}
- d->addAttr(::new (S.Context) RegparmAttr(Attr.getLoc(), S.Context,
- NumParams.getZExtValue()));
+ return false;
}
static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9be04e5fb6..f6abe55383 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -8297,32 +8297,51 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) {
void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
assert(ParamInfo.getIdentifier()==0 && "block-id should have no identifier!");
+ assert(ParamInfo.getContext() == Declarator::BlockLiteralContext);
BlockScopeInfo *CurBlock = getCurBlock();
TypeSourceInfo *Sig = GetTypeForDeclarator(ParamInfo, CurScope);
- CurBlock->TheDecl->setSignatureAsWritten(Sig);
QualType T = Sig->getType();
- bool isVariadic;
- QualType RetTy;
- if (const FunctionType *Fn = T->getAs<FunctionType>()) {
- CurBlock->FunctionType = T;
- RetTy = Fn->getResultType();
- isVariadic =
- !isa<FunctionProtoType>(Fn) || cast<FunctionProtoType>(Fn)->isVariadic();
- } else {
- RetTy = T;
- isVariadic = false;
- }
+ // GetTypeForDeclarator always produces a function type for a block
+ // literal signature. Furthermore, it is always a FunctionProtoType
+ // unless the function was written with a typedef.
+ assert(T->isFunctionType() &&
+ "GetTypeForDeclarator made a non-function block signature");
- CurBlock->TheDecl->setIsVariadic(isVariadic);
+ // Look for an explicit signature in that function type.
+ FunctionProtoTypeLoc ExplicitSignature;
- // Don't allow returning an array by value.
- if (RetTy->isArrayType()) {
- Diag(ParamInfo.getSourceRange().getBegin(), diag::err_block_returns_array);
- return;
+ TypeLoc tmp = Sig->getTypeLoc().IgnoreParens();
+ if (isa<FunctionProtoTypeLoc>(tmp)) {
+ ExplicitSignature = cast<FunctionProtoTypeLoc>(tmp);
+
+ // Check whether that explicit signature was synthesized by
+ // GetTypeForDeclarator. If so, don't save that as part of the
+ // written signature.
+ if (ExplicitSignature.getLParenLoc() ==
+ ExplicitSignature.getRParenLoc()) {
+ // This would be much cheaper if we stored TypeLocs instead of
+ // TypeSourceInfos.
+ TypeLoc Result = ExplicitSignature.getResultLoc();
+ unsigned Size = Result.getFullDataSize();
+ Sig = Context.CreateTypeSourceInfo(Result.getType(), Size);
+ Sig->getTypeLoc().initializeFullCopy(Result, Size);
+
+ ExplicitSignature = FunctionProtoTypeLoc();
+ }
}
+ CurBlock->TheDecl->setSignatureAsWritten(Sig);
+ CurBlock->FunctionType = T;
+
+ const FunctionType *Fn = T->getAs<FunctionType>();
+ QualType RetTy = Fn->getResultType();
+ bool isVariadic =
+ (isa<FunctionProtoType>(Fn) && cast<FunctionProtoType>(Fn)->isVariadic());
+
+ CurBlock->TheDecl->setIsVariadic(isVariadic);
+
// Don't allow returning a objc interface by value.
if (RetTy->isObjCObjectType()) {
Diag(ParamInfo.getSourceRange().getBegin(),
@@ -8339,11 +8358,9 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
// Push block parameters from the declarator if we had them.
llvm::SmallVector<ParmVarDecl*, 8> Params;
- if (isa<FunctionProtoType>(T.IgnoreParens())) {
- FunctionProtoTypeLoc TL
- = cast<FunctionProtoTypeLoc>(Sig->getTypeLoc().IgnoreParens());
- for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) {
- ParmVarDecl *Param = TL.getArg(I);
+ if (ExplicitSignature) {
+ for (unsigned I = 0, E = ExplicitSignature.getNumArgs(); I != E; ++I) {
+ ParmVarDecl *Param = ExplicitSignature.getArg(I);
if (Param->getIdentifier() == 0 &&
!Param->isImplicit() &&
!Param->isInvalidDecl() &&
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 6ddbe13b27..3ce96612c2 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1153,7 +1153,7 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
QualType FnRetType = CurBlock->ReturnType;
- if (CurBlock->TheDecl->hasAttr<NoReturnAttr>()) {
+ if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) {
Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName();
return StmtError();
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;