diff options
-rw-r--r-- | include/clang/AST/Type.h | 5 | ||||
-rw-r--r-- | include/clang/AST/TypeLoc.h | 14 | ||||
-rw-r--r-- | include/clang/Sema/AttributeList.h | 9 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 24 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/AST/TypeLoc.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 144 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 61 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 884 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 21 | ||||
-rw-r--r-- | test/Sema/block-return.c | 2 | ||||
-rw-r--r-- | test/Sema/stdcall-fastcall.c | 2 |
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; |