From 04a67a6aa3dfdc92d57f7f8d93ba397348c868a4 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 5 Feb 2010 21:31:56 +0000 Subject: [PATCH] Standardize the parsing of function type attributes in a way that follows (as conservatively as possible) gcc's current behavior: attributes written on return types that don't apply there are applied to the function instead, etc. Only parse CC attributes as type attributes, not as decl attributes; don't accepet noreturn as a decl attribute on ValueDecls, either (it still needs to apply to other decls, like blocks). Consistently consume CC/noreturn information throughout codegen; enforce this by removing their default values in CodeGenTypes::getFunctionInfo(). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95436 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 14 ++ include/clang/AST/Type.h | 2 + include/clang/Basic/DiagnosticSemaKinds.td | 9 +- lib/AST/ASTContext.cpp | 20 +- lib/AST/Type.cpp | 11 + lib/CodeGen/CGBlocks.cpp | 18 +- lib/CodeGen/CGCXX.cpp | 8 +- lib/CodeGen/CGCall.cpp | 76 ++++--- lib/CodeGen/CGCall.h | 9 + lib/CodeGen/CGClass.cpp | 22 +- lib/CodeGen/CGException.cpp | 13 +- lib/CodeGen/CGExpr.cpp | 18 +- lib/CodeGen/CGExprCXX.cpp | 15 +- lib/CodeGen/CGObjC.cpp | 9 +- lib/CodeGen/CGObjCGNU.cpp | 9 +- lib/CodeGen/CGObjCMac.cpp | 18 +- lib/CodeGen/CodeGenFunction.cpp | 4 +- lib/CodeGen/CodeGenTypes.h | 15 +- lib/Sema/Sema.h | 4 +- lib/Sema/SemaChecking.cpp | 3 +- lib/Sema/SemaDecl.cpp | 29 +-- lib/Sema/SemaDeclAttr.cpp | 129 +----------- lib/Sema/SemaStmt.cpp | 3 +- lib/Sema/SemaType.cpp | 234 +++++++++++++-------- test/CodeGen/attributes.c | 7 + test/CodeGen/stdcall-fastcall.c | 8 +- test/Sema/attr-noreturn.c | 2 +- test/Sema/callingconv.c | 7 +- test/Sema/stdcall-fastcall.c | 8 +- 29 files changed, 373 insertions(+), 351 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 6fa6e30deb..ad9444b68b 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -971,6 +971,20 @@ public: NestedNameSpecifier * getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS); + /// \brief Retrieves the canonical representation of the given + /// calling convention. + CallingConv getCanonicalCallConv(CallingConv CC) { + if (CC == CC_C) + return CC_Default; + return CC; + } + + /// \brief Determines whether two calling conventions name the same + /// calling convention. + bool isSameCallConv(CallingConv lcc, CallingConv rcc) { + return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc)); + } + /// \brief Retrieves the "canonical" template name that refers to a /// given template. /// diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 4e213ed785..911c30d65b 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1761,6 +1761,8 @@ public: bool getNoReturnAttr() const { return NoReturn; } CallingConv getCallConv() const { return (CallingConv)CallConv; } + static llvm::StringRef getNameForCallConv(CallingConv CC); + static bool classof(const Type *T) { return T->getTypeClass() == FunctionNoProto || T->getTypeClass() == FunctionProto; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4d8114d617..cecd757a65 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -741,13 +741,18 @@ def err_attribute_wrong_decl_type : Error< "parameter or Objective-C method |function, method or block|" "virtual method or class|function, method, or parameter|class|virtual method" "|member}1 types">; +def warn_function_attribute_wrong_type : Warning< + "%0 only applies to function types; type here is %1">; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">; +def err_cconv_change : Error< + "function declared '%0' here was previously declared " + "%select{'%2'|without calling convention}1">; def err_cconv_knr : Error< - "function with no prototype cannot use '%0' calling convention">; + "function with no prototype cannot use %0 calling convention">; def err_cconv_varargs : Error< - "variadic function cannot use '%0' calling convention">; + "variadic function cannot use %0 calling convention">; def warn_impcast_vector_scalar : Warning< "implicit cast turns vector to scalar: %0 to %1">, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4c93513956..7e03f56f62 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1716,12 +1716,6 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType, return QualType(New, 0); } -static CallingConv getCanonicalCallingConv(CallingConv CC) { - if (CC == CC_C) - return CC_Default; - return CC; -} - /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, @@ -1738,9 +1732,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, QualType Canonical; if (!ResultTy.isCanonical() || - getCanonicalCallingConv(CallConv) != CallConv) { + getCanonicalCallConv(CallConv) != CallConv) { Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, - getCanonicalCallingConv(CallConv)); + getCanonicalCallConv(CallConv)); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = @@ -1784,7 +1778,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; - if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) { + if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) { llvm::SmallVector CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) @@ -1794,7 +1788,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray, CanonicalArgs.data(), NumArgs, isVariadic, TypeQuals, false, false, 0, 0, NoReturn, - getCanonicalCallingConv(CallConv)); + getCanonicalCallConv(CallConv)); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = @@ -4300,10 +4294,6 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) { return !mergeTypes(LHS, RHS).isNull(); } -static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) { - return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc)); -} - QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { const FunctionType *lbase = lhs->getAs(); const FunctionType *rbase = rhs->getAs(); @@ -4328,7 +4318,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { CallingConv lcc = lbase->getCallConv(); CallingConv rcc = rbase->getCallConv(); // Compatible functions must have compatible calling conventions - if (!isSameCallingConvention(lcc, rcc)) + if (!isSameCallConv(lcc, rcc)) return QualType(); if (lproto && rproto) { // two C99 style function prototypes diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 4e74759676..92498be2f5 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -810,6 +810,17 @@ const char *BuiltinType::getName(const LangOptions &LO) const { } } +llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { + switch (CC) { + case CC_Default: llvm_unreachable("no name for default cc"); + default: return ""; + + case CC_C: return "cdecl"; + case CC_X86StdCall: return "stdcall"; + case CC_X86FastCall: return "fastcall"; + } +} + void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, arg_type_iterator ArgTys, unsigned NumArgs, bool isVariadic, diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 5da6187c51..05d138b2a2 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -496,10 +496,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, // Load the function. llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp"); - QualType ResultType = FnType->getAs()->getResultType(); + const FunctionType *FuncTy = FnType->getAs(); + QualType ResultType = FuncTy->getResultType(); const CGFunctionInfo &FnInfo = - CGM.getTypes().getFunctionInfo(ResultType, Args); + CGM.getTypes().getFunctionInfo(ResultType, Args, FuncTy->getCallConv(), + FuncTy->getNoReturnAttr()); // Cast the function pointer to the right type. const llvm::Type *BlockFTy = @@ -704,6 +706,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, const FunctionType *BlockFunctionType = BExpr->getFunctionType(); QualType ResultType; + CallingConv CC = BlockFunctionType->getCallConv(); + bool NoReturn = BlockFunctionType->getNoReturnAttr(); bool IsVariadic; if (const FunctionProtoType *FTy = dyn_cast(BlockFunctionType)) { @@ -742,7 +746,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, Args.push_back(std::make_pair(*i, (*i)->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(ResultType, Args); + CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); @@ -867,7 +871,7 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -948,7 +952,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. @@ -1032,7 +1036,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) { Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); @@ -1095,7 +1099,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, Args.push_back(std::make_pair(Src, Src->getType())); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args); + CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); CodeGenTypes &Types = CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 4323f84d96..28c4c6b4b5 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -165,7 +165,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, GlobalDecl GD, bool Extern, const CovariantThunkAdjustment &Adjustment) { const CXXMethodDecl *MD = cast(GD.getDecl()); - QualType ResultType = MD->getType()->getAs()->getResultType(); + const FunctionProtoType *FPT = MD->getType()->getAs(); + QualType ResultType = FPT->getResultType(); FunctionArgList Args; ImplicitParamDecl *ThisDecl = @@ -190,7 +191,6 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, StartFunction(FD, ResultType, Fn, Args, SourceLocation()); // generate body - const FunctionProtoType *FPT = MD->getType()->getAs(); const llvm::Type *Ty = CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), FPT->isVariadic()); @@ -232,7 +232,9 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); } - RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs, + FPT->getCallConv(), + FPT->getNoReturnAttr()), Callee, ReturnValueSlot(), CallArgs, MD); if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) { bool CanBeZero = !(ResultType->isReferenceType() diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index ce361f08fe..7a47d5bcc0 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -33,12 +33,19 @@ using namespace CodeGen; // FIXME: Use iterator and sidestep silly type array creation. +static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) { + switch (CC) { + default: return llvm::CallingConv::C; + case CC_X86StdCall: return llvm::CallingConv::X86_StdCall; + case CC_X86FastCall: return llvm::CallingConv::X86_FastCall; + } +} + const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { - // FIXME: Set calling convention correctly, it needs to be associated with the - // type somehow. return getFunctionInfo(FTNP->getResultType(), - llvm::SmallVector(), 0); + llvm::SmallVector(), + FTNP->getCallConv(), FTNP->getNoReturnAttr()); } const @@ -47,20 +54,19 @@ CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) { // FIXME: Kill copy. for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - // FIXME: Set calling convention correctly, it needs to be associated with the - // type somehow. - return getFunctionInfo(FTP->getResultType(), ArgTys, 0); + return getFunctionInfo(FTP->getResultType(), ArgTys, + FTP->getCallConv(), FTP->getNoReturnAttr()); } -static unsigned getCallingConventionForDecl(const Decl *D) { +static CallingConv getCallingConventionForDecl(const Decl *D) { // Set the appropriate calling convention for the Function. if (D->hasAttr()) - return llvm::CallingConv::X86_StdCall; + return CC_X86StdCall; if (D->hasAttr()) - return llvm::CallingConv::X86_FastCall; + return CC_X86FastCall; - return llvm::CallingConv::C; + return CC_C; } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, @@ -75,7 +81,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, // FIXME: Set calling convention correctly, it needs to be associated with the // type somehow. - return getFunctionInfo(FTP->getResultType(), ArgTys, 0); + return getFunctionInfo(FTP->getResultType(), ArgTys, + FTP->getCallConv(), FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { @@ -87,8 +94,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { const FunctionProtoType *FTP = MD->getType()->getAs(); for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - getCallingConventionForDecl(MD)); + return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), + FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, @@ -105,8 +112,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, const FunctionProtoType *FTP = D->getType()->getAs(); for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - getCallingConventionForDecl(D)); + return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), + FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, @@ -123,8 +130,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, const FunctionProtoType *FTP = D->getType()->getAs(); for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) ArgTys.push_back(FTP->getArgType(i)); - return getFunctionInfo(FTP->getResultType(), ArgTys, - getCallingConventionForDecl(D)); + return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(), + FTP->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { @@ -132,19 +139,19 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { if (MD->isInstance()) return getFunctionInfo(MD); - unsigned CallingConvention = getCallingConventionForDecl(FD); const FunctionType *FTy = FD->getType()->getAs(); if (const FunctionNoProtoType *FNTP = dyn_cast(FTy)) return getFunctionInfo(FNTP->getResultType(), llvm::SmallVector(), - CallingConvention); + FNTP->getCallConv(), FNTP->getNoReturnAttr()); const FunctionProtoType *FPT = cast(FTy); llvm::SmallVector ArgTys; // FIXME: Kill copy. for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i) ArgTys.push_back(FPT->getArgType(i)); - return getFunctionInfo(FPT->getResultType(), ArgTys, CallingConvention); + return getFunctionInfo(FPT->getResultType(), ArgTys, + FPT->getCallConv(), FPT->getNoReturnAttr()); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { @@ -156,37 +163,43 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { e = MD->param_end(); i != e; ++i) ArgTys.push_back((*i)->getType()); return getFunctionInfo(MD->getResultType(), ArgTys, - getCallingConventionForDecl(MD)); + getCallingConventionForDecl(MD), + /*NoReturn*/ false); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CallArgList &Args, - unsigned CallingConvention){ + CallingConv CC, + bool NoReturn) { // FIXME: Kill copy. llvm::SmallVector ArgTys; for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CallingConvention); + return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const FunctionArgList &Args, - unsigned CallingConvention){ + CallingConv CC, + bool NoReturn) { // FIXME: Kill copy. llvm::SmallVector ArgTys; for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) ArgTys.push_back(i->second); - return getFunctionInfo(ResTy, ArgTys, CallingConvention); + return getFunctionInfo(ResTy, ArgTys, CC, NoReturn); } const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const llvm::SmallVector &ArgTys, - unsigned CallingConvention){ + CallingConv CallConv, + bool NoReturn) { + unsigned CC = ClangCallConvToLLVMCallConv(CallConv); + // Lookup or create unique function info. llvm::FoldingSetNodeID ID; - CGFunctionInfo::Profile(ID, CallingConvention, ResTy, + CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy, ArgTys.begin(), ArgTys.end()); void *InsertPos = 0; @@ -195,7 +208,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, return *FI; // Construct the function info. - FI = new CGFunctionInfo(CallingConvention, ResTy, ArgTys); + FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys); FunctionInfos.InsertNode(FI, InsertPos); // Compute ABI information. @@ -205,10 +218,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, } CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, + bool _NoReturn, QualType ResTy, const llvm::SmallVector &ArgTys) : CallingConvention(_CallingConvention), - EffectiveCallingConvention(_CallingConvention) + EffectiveCallingConvention(_CallingConvention), + NoReturn(_NoReturn) { NumArgs = ArgTys.size(); Args = new ArgInfo[1 + NumArgs]; @@ -490,6 +505,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, CallingConv = FI.getEffectiveCallingConvention(); + if (FI.isNoReturn()) + FuncAttrs |= llvm::Attribute::NoReturn; + // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr()) diff --git a/lib/CodeGen/CGCall.h b/lib/CodeGen/CGCall.h index 427ab5f4cb..9601e9ae9a 100644 --- a/lib/CodeGen/CGCall.h +++ b/lib/CodeGen/CGCall.h @@ -69,6 +69,9 @@ namespace CodeGen { /// depend on the ABI. unsigned EffectiveCallingConvention; + /// Whether this function is noreturn. + bool NoReturn; + unsigned NumArgs; ArgInfo *Args; @@ -77,6 +80,7 @@ namespace CodeGen { typedef ArgInfo *arg_iterator; CGFunctionInfo(unsigned CallingConvention, + bool NoReturn, QualType ResTy, const llvm::SmallVector &ArgTys); ~CGFunctionInfo() { delete[] Args; } @@ -88,6 +92,8 @@ namespace CodeGen { unsigned arg_size() const { return NumArgs; } + bool isNoReturn() const { return NoReturn; } + /// getCallingConvention - Return the user specified calling /// convention. unsigned getCallingConvention() const { return CallingConvention; } @@ -108,6 +114,7 @@ namespace CodeGen { void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getCallingConvention()); + ID.AddBoolean(NoReturn); getReturnType().Profile(ID); for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) it->type.Profile(ID); @@ -115,10 +122,12 @@ namespace CodeGen { template static void Profile(llvm::FoldingSetNodeID &ID, unsigned CallingConvention, + bool NoReturn, QualType ResTy, Iterator begin, Iterator end) { ID.AddInteger(CallingConvention); + ID.AddBoolean(NoReturn); ResTy.Profile(ID); for (; begin != end; ++begin) begin->Profile(ID); diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 70973a4560..c3901a5ae1 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -327,9 +327,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), BaseCopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - BaseCopyCtor->getType()->getAs()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + const FunctionProtoType *FPT + = BaseCopyCtor->getType()->getAs(); + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); } EmitBlock(ContinueBlock); @@ -412,8 +412,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest, RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : RValue::getAggregate(Src); CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - QualType ResultType = MD->getType()->getAs()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, MD); } EmitBlock(ContinueBlock); @@ -503,9 +502,9 @@ void CodeGenFunction::EmitClassMemberwiseCopy( // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), BaseCopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - BaseCopyCtor->getType()->getAs()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + const FunctionProtoType *FPT = + BaseCopyCtor->getType()->getAs(); + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); } } @@ -550,9 +549,7 @@ void CodeGenFunction::EmitClassCopyAssignment( RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : RValue::getAggregate(Src); CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); - QualType ResultType = - MD->getType()->getAs()->getResultType(); - EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, MD); } @@ -1197,7 +1194,8 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, llvm::SmallString<16> Name; llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount); QualType R = getContext().VoidTy; - const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args); + const CGFunctionInfo &FI + = CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index bd0461fd28..a992b459d8 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -194,9 +194,9 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), CopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - CopyCtor->getType()->getAs()->getResultType(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + const FunctionProtoType *FPT + = CopyCtor->getType()->getAs(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, CopyCtor); CGF.setInvokeDest(PrevLandingPad); } else @@ -244,9 +244,10 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, // Push the Src ptr. CallArgs.push_back(std::make_pair(RValue::get(Src), CopyCtor->getParamDecl(0)->getType())); - QualType ResultType = - CopyCtor->getType()->getAs()->getResultType(); - CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + + const FunctionProtoType *FPT + = CopyCtor->getType()->getAs(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT), Callee, ReturnValueSlot(), CallArgs, CopyCtor); } else llvm_unreachable("uncopyable object"); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 7fb79e9585..d258945079 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -1853,14 +1853,6 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); } -static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) { - switch (CC) { - default: return llvm::CallingConv::C; - case CC_X86StdCall: return llvm::CallingConv::X86_StdCall; - case CC_X86FastCall: return llvm::CallingConv::X86_FastCall; - } -} - RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, ReturnValueSlot ReturnValue, CallExpr::const_arg_iterator ArgBeg, @@ -1873,16 +1865,14 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee, CalleeType = getContext().getCanonicalType(CalleeType); - QualType FnType = cast(CalleeType)->getPointeeType(); - QualType ResultType = cast(FnType)->getResultType(); + const FunctionType *FnType + = cast(cast(CalleeType)->getPointeeType()); + QualType ResultType = FnType->getResultType(); CallArgList Args; EmitCallArgs(Args, dyn_cast(FnType), ArgBeg, ArgEnd); - unsigned CallingConvention = - ClangCallConvToLLVMCallConv(FnType->getAs()->getCallConv()); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, - CallingConvention), + return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType), Callee, ReturnValue, Args, TargetDecl); } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 2dbeaecf75..7af90b7a46 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -42,8 +42,10 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, // And the rest of the call args EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); - QualType ResultType = MD->getType()->getAs()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + QualType ResultType = FPT->getResultType(); + return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, + FPT->getCallConv(), + FPT->getNoReturnAttr()), Callee, ReturnValue, Args, MD); } @@ -244,8 +246,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, // And the rest of the call args EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); - QualType ResultType = BO->getType()->getAs()->getResultType(); - return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, + const FunctionType *BO_FPT = BO->getType()->getAs(); + return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee, ReturnValue, Args); } @@ -542,7 +544,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // Emit the call to new. RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), + EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy), CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD); // If an allocation function is declared with an empty exception specification @@ -686,8 +688,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); // Emit the call to delete. - EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), - DeleteArgs), + EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy), CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(), DeleteArgs, DeleteFD); } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index e03d7606c1..fedf16cbd9 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -190,7 +190,8 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); // FIXME: We shouldn't need to get the function info here, the // runtime already should have computed it to build the function. - RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args), + RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args, + CC_Default, false), GetPropertyFn, ReturnValueSlot(), Args); // We need to fix the type here. Ivars with copy & retain are // always objects so we don't need to worry about complex or @@ -278,7 +279,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, getContext().BoolTy)); // FIXME: We shouldn't need to get the function info here, the runtime // already should have computed it to build the function. - EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args), SetPropertyFn, + EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, + CC_Default, false), SetPropertyFn, ReturnValueSlot(), Args); } else { // FIXME: Find a clean way to avoid AST node creation. @@ -554,7 +556,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ getContext().getObjCIdType())); // FIXME: We shouldn't need to get the function info here, the runtime already // should have computed it to build the function. - EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2), + EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2, + CC_Default, false), EnumerationMutationFn, ReturnValueSlot(), Args2); EmitBlock(WasNotMutated); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index ace38960b0..d14f954773 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -464,7 +464,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -571,7 +572,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -1686,7 +1688,8 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { llvm::SmallVector Params; Params.push_back(ASTIdTy); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 0dcbe829e2..2f931bd637 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -305,7 +305,8 @@ public: Params.push_back(Ctx.LongTy); Params.push_back(Ctx.BoolTy); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(IdType, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(IdType, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_getProperty"); } @@ -323,7 +324,8 @@ public: Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_setProperty"); } @@ -334,7 +336,8 @@ public: llvm::SmallVector Params; Params.push_back(Ctx.getObjCIdType()); const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false); + Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, + CC_Default, false), false); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); } @@ -1554,7 +1557,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); - const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); @@ -5089,7 +5093,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( // FIXME. This is too much work to get the ABI-specific result type needed to // find the message name. const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, - llvm::SmallVector()); + llvm::SmallVector(), + CC_Default, false); llvm::Constant *Fn = 0; std::string Name("\01l_"); if (CGM.ReturnTypeUsesSret(FnInfo)) { @@ -5163,7 +5168,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( ActualArgs.push_back(std::make_pair(RValue::get(Arg1), ObjCTypes.MessageRefCPtrTy)); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); - const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs); + const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs, + CC_Default, false); llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0); Callee = CGF.Builder.CreateLoad(Callee); const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 520742e76d..44ed9db347 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -196,7 +196,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } // FIXME: Leaked. - CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args); + // CC info is ignored, hopefully? + CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args, + CC_Default, false); if (RetTy->isVoidType()) { // Void type; nothing to return. diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index aa1880b41f..49da15de23 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -198,6 +198,12 @@ public: const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D, CXXDtorType Type); + const CGFunctionInfo &getFunctionInfo(const CallArgList &Args, + const FunctionType *Ty) { + return getFunctionInfo(Ty->getResultType(), Args, + Ty->getCallConv(), Ty->getNoReturnAttr()); + } + // getFunctionInfo - Get the function info for a member function. const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, const FunctionProtoType *FTP); @@ -207,13 +213,16 @@ public: /// specified, the "C" calling convention will be used. const CGFunctionInfo &getFunctionInfo(QualType ResTy, const CallArgList &Args, - unsigned CallingConvention = 0); + CallingConv CC, + bool NoReturn); const CGFunctionInfo &getFunctionInfo(QualType ResTy, const FunctionArgList &Args, - unsigned CallingConvention = 0); + CallingConv CC, + bool NoReturn); const CGFunctionInfo &getFunctionInfo(QualType RetTy, const llvm::SmallVector &ArgTys, - unsigned CallingConvention = 0); + CallingConv CC, + bool NoReturn); public: // These are internal details of CGT that shouldn't be used externally. /// addFieldInfo - Assign field number to field FD. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6a7590997c..dfd8f3461e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -559,10 +559,8 @@ public: //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // + QualType adjustParameterType(QualType T); - void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL, - bool HandleCallConvAttributes = false, - bool HandleOnlyCallConv = false); QualType BuildPointerType(QualType T, unsigned Quals, SourceLocation Loc, DeclarationName Entity); QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index cba3c60661..76ff8dc7cb 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -2500,7 +2500,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body, return; if (FD->getResultType()->isVoidType()) ReturnsVoid = true; - if (FD->hasAttr()) + if (FD->hasAttr() || + FD->getType()->getAs()->getNoReturnAttr()) HasNoReturn = true; } else if (ObjCMethodDecl *MD = dyn_cast(D)) { if (MD->getResultType()->isVoidType()) diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1415f73f64..52fc9b74e0 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -908,14 +908,6 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx, return Sema::CXXCopyAssignment; } -static const char* getCallConvName(CallingConv CC) { - switch (CC) { - default: return "cdecl"; - case CC_X86StdCall: return "stdcall"; - case CC_X86FastCall: return "fastcall"; - } -} - /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -992,14 +984,25 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { NewQType = Context.getCallConvType(NewQType, OldType->getCallConv()); New->setType(NewQType); NewQType = Context.getCanonicalType(NewQType); - } else if (OldType->getCallConv() != NewType->getCallConv()) { + } else if (!Context.isSameCallConv(OldType->getCallConv(), + NewType->getCallConv())) { // Calling conventions really aren't compatible, so complain. - Diag(New->getLocation(), diag::err_attributes_are_not_compatible) - << getCallConvName(NewType->getCallConv()) - << getCallConvName(OldType->getCallConv()); + Diag(New->getLocation(), diag::err_cconv_change) + << FunctionType::getNameForCallConv(NewType->getCallConv()) + << (OldType->getCallConv() == CC_Default) + << (OldType->getCallConv() == CC_Default ? "" : + FunctionType::getNameForCallConv(OldType->getCallConv())); + Diag(Old->getLocation(), diag::note_previous_declaration); return true; } + // FIXME: diagnose the other way around? + if (OldType->getNoReturnAttr() && !NewType->getNoReturnAttr()) { + NewQType = Context.getNoReturnType(NewQType); + New->setType(NewQType); + assert(NewQType.isCanonical()); + } + if (getLangOptions().CPlusPlus) { // (C++98 13.1p2): // Certain function declarations cannot be overloaded: @@ -4383,7 +4386,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } if (Context.BuiltinInfo.isNoReturn(BuiltinID)) - FD->addAttr(::new (Context) NoReturnAttr()); + FD->setType(Context.getNoReturnType(FD->getType())); if (Context.BuiltinInfo.isNoThrow(BuiltinID)) FD->addAttr(::new (Context) NoThrowAttr()); if (Context.BuiltinInfo.isConst(BuiltinID)) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 681a3b7813..01e8fda2eb 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -391,6 +391,11 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr, } static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { + // Don't apply as a decl attribute to ValueDecl. + // FIXME: probably ought to diagnose this. + if (isa(d)) + return; + if (HandleCommonNoReturnAttr(d, Attr, S)) d->addAttr(::new (S.Context) NoReturnAttr()); } @@ -404,7 +409,7 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isFunctionOrMethod(d) && !isa(d)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << 8; /*function, method, or parameter*/ + << Attr.getName() << 8 /*function, method, or parameter*/; return; } // FIXME: Actually store the attribute on the declaration @@ -940,120 +945,6 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { D->addAttr(::new (S.Context) SectionAttr(SE->getString())); } -static void HandleCDeclAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Attribute has no arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // Attribute can be applied only to functions. - // If we try to apply it to a function pointer, don't warn, but don't - // do anything, either. All the function-pointer stuff is handled in - // SemaType.cpp. - ValueDecl *VD = dyn_cast(d); - if (VD && VD->getType()->isFunctionPointerType()) - return; - if (!isa(d)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; - return; - } - - // cdecl and fastcall attributes are mutually incompatible. - if (d->getAttr()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "cdecl" << "fastcall"; - return; - } - - // cdecl and stdcall attributes are mutually incompatible. - if (d->getAttr()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "cdecl" << "stdcall"; - return; - } - - d->addAttr(::new (S.Context) CDeclAttr()); -} - - -static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Attribute has no arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // Attribute can be applied only to functions. - // If we try to apply it to a function pointer, don't warn, but don't - // do anything, either. All the function-pointer stuff is handled in - // SemaType.cpp. - ValueDecl *VD = dyn_cast(d); - if (VD && VD->getType()->isFunctionPointerType()) - return; - if (!isa(d)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; - return; - } - - // stdcall and fastcall attributes are mutually incompatible. - if (d->getAttr()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "stdcall" << "fastcall"; - return; - } - - d->addAttr(::new (S.Context) StdCallAttr()); -} - -/// Diagnose the use of a non-standard calling convention on the given -/// function. -static void DiagnoseCConv(FunctionDecl *D, const char *CConv, - SourceLocation Loc, Sema &S) { - if (!D->hasPrototype()) { - S.Diag(Loc, diag::err_cconv_knr) << CConv; - return; - } - - const FunctionProtoType *T = D->getType()->getAs(); - if (T->isVariadic()) { - S.Diag(Loc, diag::err_cconv_varargs) << CConv; - return; - } -} - -static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // Attribute has no arguments. - if (Attr.getNumArgs() != 0) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; - return; - } - - // If we try to apply it to a function pointer, don't warn, but don't - // do anything, either. All the function-pointer stuff is handled in - // SemaType.cpp. - ValueDecl *VD = dyn_cast(d); - if (VD && VD->getType()->isFunctionPointerType()) - return; - if (!isa(d)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; - return; - } - - DiagnoseCConv(cast(d), "fastcall", Attr.getLoc(), S); - - // stdcall and fastcall attributes are mutually incompatible. - if (d->getAttr()) { - S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << "fastcall" << "stdcall"; - return; - } - - d->addAttr(::new (S.Context) FastCallAttr()); -} static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. @@ -1926,7 +1817,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_base_check: HandleBaseCheckAttr (D, Attr, S); break; case AttributeList::AT_carries_dependency: HandleDependencyAttr (D, Attr, S); break; - case AttributeList::AT_cdecl: HandleCDeclAttr (D, Attr, S); break; case AttributeList::AT_constructor: HandleConstructorAttr (D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; case AttributeList::AT_destructor: HandleDestructorAttr (D, Attr, S); break; @@ -1935,7 +1825,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_ext_vector_type: HandleExtVectorTypeAttr(scope, D, Attr, S); break; - case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break; case AttributeList::AT_final: HandleFinalAttr (D, Attr, S); break; case AttributeList::AT_format: HandleFormatAttr (D, Attr, S); break; case AttributeList::AT_format_arg: HandleFormatArgAttr (D, Attr, S); break; @@ -1958,7 +1847,6 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; - case AttributeList::AT_stdcall: HandleStdCallAttr (D, Attr, S); break; case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; case AttributeList::AT_used: HandleUsedAttr (D, Attr, S); break; @@ -1987,6 +1875,11 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, case AttributeList::AT_no_instrument_function: // Interacts with -pg. // Just ignore break; + case AttributeList::AT_stdcall: + case AttributeList::AT_cdecl: + case AttributeList::AT_fastcall: + // These are all treated as type attributes. + break; default: // Ask target about the attribute. const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index a1aefee78b..ad296eb363 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1043,7 +1043,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) { QualType FnRetType; if (const FunctionDecl *FD = getCurFunctionDecl()) { FnRetType = FD->getResultType(); - if (FD->hasAttr()) + if (FD->hasAttr() || + FD->getType()->getAs()->getNoReturnAttr()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << getCurFunctionOrMethodDecl()->getDeclName(); } else if (ObjCMethodDecl *MD = getCurMethodDecl()) diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 60f3b19060..3ef13a2aba 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -68,12 +68,41 @@ static bool isOmittedBlockReturnType(const Declarator &D) { return false; } +typedef std::pair DelayedAttribute; +typedef llvm::SmallVectorImpl DelayedAttributeSet; + +static void ProcessTypeAttributeList(Sema &S, QualType &Type, + 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; + Attrs.clear(); +} + +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; + } + Attrs.clear(); +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param D the declarator containing the declaration specifier. /// \returns The type described by the declaration specifiers. This function /// never returns null. -static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ +static QualType ConvertDeclSpecToType(Sema &TheSema, + Declarator &TheDeclarator, + DelayedAttributeSet &Delayed) { // FIXME: Should move the logic from DeclSpec::Finish to here for validity // checking. const DeclSpec &DS = TheDeclarator.getDeclSpec(); @@ -356,7 +385,7 @@ static QualType ConvertDeclSpecToType(Declarator &TheDeclarator, Sema &TheSema){ // 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()) - TheSema.ProcessTypeAttributeList(Result, AL); + ProcessTypeAttributeList(TheSema, Result, AL, Delayed); // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -890,12 +919,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // have a type. QualType T; + llvm::SmallVector FnAttrsFromDeclSpec; + switch (D.getName().getKind()) { case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: - T = ConvertDeclSpecToType(D, *this); + T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec); if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned()) *OwnedDecl = cast((Decl *)D.getDeclSpec().getTypeRep()); @@ -967,6 +998,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.getIdentifier()) Name = D.getIdentifier(); + llvm::SmallVector 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 :). @@ -1186,6 +1219,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, FTI.hasAnyExceptionSpec, Exceptions.size(), Exceptions.data()); } + + // 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: @@ -1244,9 +1284,11 @@ QualType 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(T, AL, true); + ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk); } if (getLangOptions().CPlusPlus && T->isFunctionType()) { @@ -1276,13 +1318,18 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } } - // If there were any type attributes applied to the decl itself (not the - // type, apply the type attribute to the type!) - if (const AttributeList *Attrs = D.getAttributes()) - ProcessTypeAttributeList(T, Attrs, true); - // Also look in the decl spec. - if (const AttributeList *Attrs = D.getDeclSpec().getAttributes()) - ProcessTypeAttributeList(T, Attrs, true, true); + // 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, Attrs, FnAttrsFromPreviousChunk); + + DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk); if (TInfo) { if (D.isInvalidType()) @@ -1620,36 +1667,6 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, Type = S.Context.getAddrSpaceQualType(Type, ASIdx); } -/// HandleCDeclTypeAttribute - Process the cdecl attribute on the -/// specified type. The attribute contains 0 arguments. -static void HandleCDeclTypeAttribute(QualType &Type, - const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) - return; - - // We only apply this to a pointer to function. - if (!Type->isFunctionPointerType() - && !Type->isFunctionType()) - return; - - Type = S.Context.getCallConvType(Type, CC_C); -} - -/// HandleFastCallTypeAttribute - Process the fastcall attribute on the -/// specified type. The attribute contains 0 arguments. -static void HandleFastCallTypeAttribute(QualType &Type, - const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) - return; - - // We only apply this to a pointer to function. - if (!Type->isFunctionPointerType() - && !Type->isFunctionType()) - return; - - Type = S.Context.getCallConvType(Type, CC_X86FastCall); -} - /// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the /// specified type. The attribute contains 1 argument, weak or strong. static void HandleObjCGCTypeAttribute(QualType &Type, @@ -1683,35 +1700,79 @@ static void HandleObjCGCTypeAttribute(QualType &Type, Type = S.Context.getObjCGCQualType(Type, GCAttr); } -/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the -/// specified type. The attribute contains 0 arguments. -static void HandleNoReturnTypeAttribute(QualType &Type, - const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) - return; +/// Process an individual function attribute. Returns true if the +/// attribute does not make sense to apply to this type. +bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { + if (Attr.getKind() == AttributeList::AT_noreturn) { + // Complain immediately if the arg count is wrong. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return false; + } - // We only apply this to a pointer to function or a pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType()) - return; + // Delay if this is not a function or pointer to block. + if (!Type->isFunctionPointerType() + && !Type->isBlockPointerType() + && !Type->isFunctionType()) + return true; - Type = S.Context.getNoReturnType(Type); -} + // Otherwise we can process right away. + Type = S.Context.getNoReturnType(Type); + return false; + } -/// HandleStdCallTypeAttribute - Process the stdcall attribute on the -/// specified type. The attribute contains 0 arguments. -static void HandleStdCallTypeAttribute(QualType &Type, - const AttributeList &Attr, Sema &S) { - if (Attr.getNumArgs() != 0) - return; + // Otherwise, a calling convention. + if (Attr.getNumArgs() != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + return false; + } - // We only apply this to a pointer to function. - if (!Type->isFunctionPointerType() - && !Type->isFunctionType()) - return; + QualType T = Type; + if (const PointerType *PT = Type->getAs()) + T = PT->getPointeeType(); + const FunctionType *Fn = T->getAs(); - Type = S.Context.getCallConvType(Type, CC_X86StdCall); + // Delay if the type didn't work out to a function. + if (!Fn) return true; + + // TODO: diagnose uses of these conventions on the wrong target. + CallingConv CC; + 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; + default: llvm_unreachable("unexpected attribute kind"); return false; + } + + CallingConv CCOld = Fn->getCallConv(); + if (CC == CCOld) return false; + + if (CCOld != CC_Default) { + // Should we diagnose reapplications of the same convention? + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << FunctionType::getNameForCallConv(CC) + << FunctionType::getNameForCallConv(CCOld); + return false; + } + + // Diagnose the use of X86 fastcall on varargs or unprototyped functions. + if (CC == CC_X86FastCall) { + if (isa(Fn)) { + S.Diag(Attr.getLoc(), diag::err_cconv_knr) + << FunctionType::getNameForCallConv(CC); + return false; + } + + const FunctionProtoType *FnP = cast(Fn); + if (FnP->isVariadic()) { + S.Diag(Attr.getLoc(), diag::err_cconv_varargs) + << FunctionType::getNameForCallConv(CC); + return false; + } + } + + Type = S.Context.getCallConvType(Type, CC); + return false; } /// HandleVectorSizeAttribute - this attribute is only applicable to integral @@ -1761,12 +1822,9 @@ static void HandleVectorSizeAttr(QualType& CurType, const AttributeList &Attr, S CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, false, false); } -void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL, - bool HandleCallConvAttributes, - bool HandleOnlyCallConv) { - if(HandleOnlyCallConv) - assert(HandleCallConvAttributes && "Can't not handle call-conv attributes" - " while only handling them!"); +void ProcessTypeAttributeList(Sema &S, QualType &Result, + const AttributeList *AL, + DelayedAttributeSet &FnAttrs) { // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the // type, but others can be present in the type specifiers even though they @@ -1776,33 +1834,23 @@ void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL, // the LeftOverAttrs list for rechaining. switch (AL->getKind()) { default: break; + case AttributeList::AT_address_space: - if (!HandleOnlyCallConv) - HandleAddressSpaceTypeAttribute(Result, *AL, *this); - break; - case AttributeList::AT_cdecl: - if (HandleCallConvAttributes) - HandleCDeclTypeAttribute(Result, *AL, *this); - break; - case AttributeList::AT_fastcall: - if (HandleCallConvAttributes) - HandleFastCallTypeAttribute(Result, *AL, *this); + HandleAddressSpaceTypeAttribute(Result, *AL, S); break; case AttributeList::AT_objc_gc: - if (!HandleOnlyCallConv) - HandleObjCGCTypeAttribute(Result, *AL, *this); - break; - case AttributeList::AT_noreturn: - if (!HandleOnlyCallConv) - HandleNoReturnTypeAttribute(Result, *AL, *this); - break; - case AttributeList::AT_stdcall: - if (HandleCallConvAttributes) - HandleStdCallTypeAttribute(Result, *AL, *this); + HandleObjCGCTypeAttribute(Result, *AL, S); break; case AttributeList::AT_vector_size: - if (!HandleOnlyCallConv) - HandleVectorSizeAttr(Result, *AL, *this); + HandleVectorSizeAttr(Result, *AL, S); + break; + + case AttributeList::AT_noreturn: + case AttributeList::AT_cdecl: + case AttributeList::AT_fastcall: + case AttributeList::AT_stdcall: + if (ProcessFnAttr(S, Result, *AL)) + FnAttrs.push_back(DelayedAttribute(AL, Result)); break; } } diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c index 68bc73daec..770ce766df 100644 --- a/test/CodeGen/attributes.c +++ b/test/CodeGen/attributes.c @@ -74,3 +74,10 @@ int t19(void) { void t20(void) { __builtin_abort(); } + +void (__attribute__((fastcall)) *fptr)(int); +void t21(void) { + fptr(10); +} +// CHECK: [[FPTRVAR:%[a-z0-9]+]] = load void (i32)** @fptr +// CHECK-NEXT: call x86_fastcallcc void [[FPTRVAR]](i32 10) diff --git a/test/CodeGen/stdcall-fastcall.c b/test/CodeGen/stdcall-fastcall.c index 24f90e0d00..bea6df39f9 100644 --- a/test/CodeGen/stdcall-fastcall.c +++ b/test/CodeGen/stdcall-fastcall.c @@ -24,10 +24,10 @@ int main(void) { // CHECK: call x86_fastcallcc void @f3() // CHECK: call x86_stdcallcc void @f4() pf1(); pf2(); pf3(); pf4(); - // CHECK: call x86_fastcallcc void %tmp() - // CHECK: call x86_stdcallcc void %tmp1() - // CHECK: call x86_fastcallcc void %tmp2() - // CHECK: call x86_stdcallcc void %tmp3() + // CHECK: call x86_fastcallcc void %{{.*}}() + // CHECK: call x86_stdcallcc void %{{.*}}() + // CHECK: call x86_fastcallcc void %{{.*}}() + // CHECK: call x86_stdcallcc void %{{.*}}() return 0; } diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c index 3f064a01c8..b17f9fd129 100644 --- a/test/Sema/attr-noreturn.c +++ b/test/Sema/attr-noreturn.c @@ -11,7 +11,7 @@ static void __attribute__((noreturn)) f0(void) { // On K&R int f1() __attribute__((noreturn)); -int g0 __attribute__((noreturn)); // expected-warning {{'noreturn' attribute only applies to function types}} +int g0 __attribute__((noreturn)); // expected-warning {{'noreturn' only applies to function types; type here is 'int'}} int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute requires 0 argument(s)}} diff --git a/test/Sema/callingconv.c b/test/Sema/callingconv.c index 0337c069f1..0752606ed9 100644 --- a/test/Sema/callingconv.c +++ b/test/Sema/callingconv.c @@ -9,13 +9,13 @@ void __attribute__((stdcall)) bar(float *a) { void __attribute__((fastcall(1))) baz(float *a) { // expected-error {{attribute requires 0 argument(s)}} } -void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use 'fastcall' calling convention}} +void __attribute__((fastcall)) test0() { // expected-error {{function with no prototype cannot use fastcall calling convention}} } void __attribute__((fastcall)) test1(void) { } -void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic function cannot use 'fastcall' calling convention}} +void __attribute__((fastcall)) test2(int a, ...) { // expected-error {{variadic function cannot use fastcall calling convention}} } void __attribute__((cdecl)) ctest0() {} @@ -33,3 +33,6 @@ void (*pctest0)() = ctest0; void ctest2() {} void (__attribute__((cdecl)) *pctest2)() = ctest2; +typedef void (__attribute__((fastcall)) *Handler) (float *); +Handler H = foo; + diff --git a/test/Sema/stdcall-fastcall.c b/test/Sema/stdcall-fastcall.c index c45f93e07c..a069526479 100644 --- a/test/Sema/stdcall-fastcall.c +++ b/test/Sema/stdcall-fastcall.c @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s // CC qualifier can be applied only to functions -int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' attribute only applies to function types}} -int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' attribute only applies to function types}} +int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' only applies to function types; type here is 'int'}} +int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' only applies to function types; type here is 'int'}} // Different CC qualifiers are not compatible void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{stdcall and fastcall attributes are not compatible}} -void __attribute__((stdcall)) foo4(); -void __attribute__((fastcall)) foo4(void); // expected-error{{fastcall and stdcall attributes are not compatible}} +void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}} +void __attribute__((fastcall)) foo4(void); // expected-error{{function declared 'fastcall' here was previously declared 'stdcall'}}