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
This commit is contained in:
John McCall 2010-02-05 21:31:56 +00:00
Родитель e50187a987
Коммит 04a67a6aa3
29 изменённых файлов: 373 добавлений и 351 удалений

Просмотреть файл

@ -971,6 +971,20 @@ public:
NestedNameSpecifier * NestedNameSpecifier *
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS); 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 /// \brief Retrieves the "canonical" template name that refers to a
/// given template. /// given template.
/// ///

Просмотреть файл

@ -1761,6 +1761,8 @@ public:
bool getNoReturnAttr() const { return NoReturn; } bool getNoReturnAttr() const { return NoReturn; }
CallingConv getCallConv() const { return (CallingConv)CallConv; } CallingConv getCallConv() const { return (CallingConv)CallConv; }
static llvm::StringRef getNameForCallConv(CallingConv CC);
static bool classof(const Type *T) { static bool classof(const Type *T) {
return T->getTypeClass() == FunctionNoProto || return T->getTypeClass() == FunctionNoProto ||
T->getTypeClass() == FunctionProto; T->getTypeClass() == FunctionProto;

Просмотреть файл

@ -741,13 +741,18 @@ def err_attribute_wrong_decl_type : Error<
"parameter or Objective-C method |function, method or block|" "parameter or Objective-C method |function, method or block|"
"virtual method or class|function, method, or parameter|class|virtual method" "virtual method or class|function, method, or parameter|class|virtual method"
"|member}1 types">; "|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< def warn_gnu_inline_attribute_requires_inline : Warning<
"'gnu_inline' attribute requires function to be marked 'inline'," "'gnu_inline' attribute requires function to be marked 'inline',"
" attribute ignored">; " 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< 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< 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< def warn_impcast_vector_scalar : Warning<
"implicit cast turns vector to scalar: %0 to %1">, "implicit cast turns vector to scalar: %0 to %1">,

Просмотреть файл

@ -1716,12 +1716,6 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
return QualType(New, 0); 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()'. /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
/// ///
QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn, QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
@ -1738,9 +1732,9 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
QualType Canonical; QualType Canonical;
if (!ResultTy.isCanonical() || if (!ResultTy.isCanonical() ||
getCanonicalCallingConv(CallConv) != CallConv) { getCanonicalCallConv(CallConv) != CallConv) {
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn, Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
getCanonicalCallingConv(CallConv)); getCanonicalCallConv(CallConv));
// Get the new insert position for the node we care about. // Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP = 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. // If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type. // The exception spec is not part of the canonical type.
QualType Canonical; QualType Canonical;
if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) { if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
llvm::SmallVector<QualType, 16> CanonicalArgs; llvm::SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs); CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i) for (unsigned i = 0; i != NumArgs; ++i)
@ -1794,7 +1788,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
CanonicalArgs.data(), NumArgs, CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals, false, isVariadic, TypeQuals, false,
false, 0, 0, NoReturn, false, 0, 0, NoReturn,
getCanonicalCallingConv(CallConv)); getCanonicalCallConv(CallConv));
// Get the new insert position for the node we care about. // Get the new insert position for the node we care about.
FunctionProtoType *NewIP = FunctionProtoType *NewIP =
@ -4300,10 +4294,6 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
return !mergeTypes(LHS, RHS).isNull(); return !mergeTypes(LHS, RHS).isNull();
} }
static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) {
return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc));
}
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
const FunctionType *lbase = lhs->getAs<FunctionType>(); const FunctionType *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>(); const FunctionType *rbase = rhs->getAs<FunctionType>();
@ -4328,7 +4318,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
CallingConv lcc = lbase->getCallConv(); CallingConv lcc = lbase->getCallConv();
CallingConv rcc = rbase->getCallConv(); CallingConv rcc = rbase->getCallConv();
// Compatible functions must have compatible calling conventions // Compatible functions must have compatible calling conventions
if (!isSameCallingConvention(lcc, rcc)) if (!isSameCallConv(lcc, rcc))
return QualType(); return QualType();
if (lproto && rproto) { // two C99 style function prototypes if (lproto && rproto) { // two C99 style function prototypes

Просмотреть файл

@ -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, void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
arg_type_iterator ArgTys, arg_type_iterator ArgTys,
unsigned NumArgs, bool isVariadic, unsigned NumArgs, bool isVariadic,

Просмотреть файл

@ -496,10 +496,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
// Load the function. // Load the function.
llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp"); llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
QualType ResultType = FnType->getAs<FunctionType>()->getResultType(); const FunctionType *FuncTy = FnType->getAs<FunctionType>();
QualType ResultType = FuncTy->getResultType();
const CGFunctionInfo &FnInfo = 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. // Cast the function pointer to the right type.
const llvm::Type *BlockFTy = const llvm::Type *BlockFTy =
@ -704,6 +706,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const FunctionType *BlockFunctionType = BExpr->getFunctionType(); const FunctionType *BlockFunctionType = BExpr->getFunctionType();
QualType ResultType; QualType ResultType;
CallingConv CC = BlockFunctionType->getCallConv();
bool NoReturn = BlockFunctionType->getNoReturnAttr();
bool IsVariadic; bool IsVariadic;
if (const FunctionProtoType *FTy = if (const FunctionProtoType *FTy =
dyn_cast<FunctionProtoType>(BlockFunctionType)) { dyn_cast<FunctionProtoType>(BlockFunctionType)) {
@ -742,7 +746,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
Args.push_back(std::make_pair(*i, (*i)->getType())); Args.push_back(std::make_pair(*i, (*i)->getType()));
const CGFunctionInfo &FI = const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(ResultType, Args); CGM.getTypes().getFunctionInfo(ResultType, Args, CC, NoReturn);
CodeGenTypes &Types = CGM.getTypes(); CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic); 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())); Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI = 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 // FIXME: We'd like to put these into a mergable by content, with
// internal linkage. // internal linkage.
@ -948,7 +952,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
Args.push_back(std::make_pair(Src, Src->getType())); Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI = 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 // FIXME: We'd like to put these into a mergable by content, with
// internal linkage. // internal linkage.
@ -1032,7 +1036,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
Args.push_back(std::make_pair(Src, Src->getType())); Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI = const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args); CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
CodeGenTypes &Types = CGM.getTypes(); CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); 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())); Args.push_back(std::make_pair(Src, Src->getType()));
const CGFunctionInfo &FI = const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args); CGM.getTypes().getFunctionInfo(R, Args, CC_Default, false);
CodeGenTypes &Types = CGM.getTypes(); CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);

Просмотреть файл

@ -165,7 +165,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
GlobalDecl GD, bool Extern, GlobalDecl GD, bool Extern,
const CovariantThunkAdjustment &Adjustment) { const CovariantThunkAdjustment &Adjustment) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
QualType ResultType = FPT->getResultType();
FunctionArgList Args; FunctionArgList Args;
ImplicitParamDecl *ThisDecl = ImplicitParamDecl *ThisDecl =
@ -190,7 +191,6 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
StartFunction(FD, ResultType, Fn, Args, SourceLocation()); StartFunction(FD, ResultType, Fn, Args, SourceLocation());
// generate body // generate body
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty = const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD), CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic()); FPT->isVariadic());
@ -232,7 +232,9 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
CallArgs.push_back(std::make_pair(EmitCallArg(Arg, ArgType), ArgType)); 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); Callee, ReturnValueSlot(), CallArgs, MD);
if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) { if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
bool CanBeZero = !(ResultType->isReferenceType() bool CanBeZero = !(ResultType->isReferenceType()

Просмотреть файл

@ -33,12 +33,19 @@ using namespace CodeGen;
// FIXME: Use iterator and sidestep silly type array creation. // 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 const
CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) { CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionNoProtoType *FTNP) {
// FIXME: Set calling convention correctly, it needs to be associated with the
// type somehow.
return getFunctionInfo(FTNP->getResultType(), return getFunctionInfo(FTNP->getResultType(),
llvm::SmallVector<QualType, 16>(), 0); llvm::SmallVector<QualType, 16>(),
FTNP->getCallConv(), FTNP->getNoReturnAttr());
} }
const const
@ -47,20 +54,19 @@ CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionProtoType *FTP) {
// FIXME: Kill copy. // FIXME: Kill copy.
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i)); ArgTys.push_back(FTP->getArgType(i));
// FIXME: Set calling convention correctly, it needs to be associated with the return getFunctionInfo(FTP->getResultType(), ArgTys,
// type somehow. FTP->getCallConv(), FTP->getNoReturnAttr());
return getFunctionInfo(FTP->getResultType(), ArgTys, 0);
} }
static unsigned getCallingConventionForDecl(const Decl *D) { static CallingConv getCallingConventionForDecl(const Decl *D) {
// Set the appropriate calling convention for the Function. // Set the appropriate calling convention for the Function.
if (D->hasAttr<StdCallAttr>()) if (D->hasAttr<StdCallAttr>())
return llvm::CallingConv::X86_StdCall; return CC_X86StdCall;
if (D->hasAttr<FastCallAttr>()) if (D->hasAttr<FastCallAttr>())
return llvm::CallingConv::X86_FastCall; return CC_X86FastCall;
return llvm::CallingConv::C; return CC_C;
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXRecordDecl *RD, 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 // FIXME: Set calling convention correctly, it needs to be associated with the
// type somehow. // type somehow.
return getFunctionInfo(FTP->getResultType(), ArgTys, 0); return getFunctionInfo(FTP->getResultType(), ArgTys,
FTP->getCallConv(), FTP->getNoReturnAttr());
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
@ -87,8 +94,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
const FunctionProtoType *FTP = MD->getType()->getAs<FunctionProtoType>(); const FunctionProtoType *FTP = MD->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i)); ArgTys.push_back(FTP->getArgType(i));
return getFunctionInfo(FTP->getResultType(), ArgTys, return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
getCallingConventionForDecl(MD)); FTP->getNoReturnAttr());
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
@ -105,8 +112,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>(); const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i)); ArgTys.push_back(FTP->getArgType(i));
return getFunctionInfo(FTP->getResultType(), ArgTys, return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
getCallingConventionForDecl(D)); FTP->getNoReturnAttr());
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
@ -123,8 +130,8 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>(); const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i) for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
ArgTys.push_back(FTP->getArgType(i)); ArgTys.push_back(FTP->getArgType(i));
return getFunctionInfo(FTP->getResultType(), ArgTys, return getFunctionInfo(FTP->getResultType(), ArgTys, FTP->getCallConv(),
getCallingConventionForDecl(D)); FTP->getNoReturnAttr());
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) { const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
@ -132,19 +139,19 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
if (MD->isInstance()) if (MD->isInstance())
return getFunctionInfo(MD); return getFunctionInfo(MD);
unsigned CallingConvention = getCallingConventionForDecl(FD);
const FunctionType *FTy = FD->getType()->getAs<FunctionType>(); const FunctionType *FTy = FD->getType()->getAs<FunctionType>();
if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy)) if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy))
return getFunctionInfo(FNTP->getResultType(), return getFunctionInfo(FNTP->getResultType(),
llvm::SmallVector<QualType, 16>(), llvm::SmallVector<QualType, 16>(),
CallingConvention); FNTP->getCallConv(), FNTP->getNoReturnAttr());
const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy); const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy);
llvm::SmallVector<QualType, 16> ArgTys; llvm::SmallVector<QualType, 16> ArgTys;
// FIXME: Kill copy. // FIXME: Kill copy.
for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i) for (unsigned i = 0, e = FPT->getNumArgs(); i != e; ++i)
ArgTys.push_back(FPT->getArgType(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) { 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) e = MD->param_end(); i != e; ++i)
ArgTys.push_back((*i)->getType()); ArgTys.push_back((*i)->getType());
return getFunctionInfo(MD->getResultType(), ArgTys, return getFunctionInfo(MD->getResultType(), ArgTys,
getCallingConventionForDecl(MD)); getCallingConventionForDecl(MD),
/*NoReturn*/ false);
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const CallArgList &Args, const CallArgList &Args,
unsigned CallingConvention){ CallingConv CC,
bool NoReturn) {
// FIXME: Kill copy. // FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys; llvm::SmallVector<QualType, 16> ArgTys;
for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); for (CallArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) i != e; ++i)
ArgTys.push_back(i->second); ArgTys.push_back(i->second);
return getFunctionInfo(ResTy, ArgTys, CallingConvention); return getFunctionInfo(ResTy, ArgTys, CC, NoReturn);
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const FunctionArgList &Args, const FunctionArgList &Args,
unsigned CallingConvention){ CallingConv CC,
bool NoReturn) {
// FIXME: Kill copy. // FIXME: Kill copy.
llvm::SmallVector<QualType, 16> ArgTys; llvm::SmallVector<QualType, 16> ArgTys;
for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end();
i != e; ++i) i != e; ++i)
ArgTys.push_back(i->second); ArgTys.push_back(i->second);
return getFunctionInfo(ResTy, ArgTys, CallingConvention); return getFunctionInfo(ResTy, ArgTys, CC, NoReturn);
} }
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys, const llvm::SmallVector<QualType, 16> &ArgTys,
unsigned CallingConvention){ CallingConv CallConv,
bool NoReturn) {
unsigned CC = ClangCallConvToLLVMCallConv(CallConv);
// Lookup or create unique function info. // Lookup or create unique function info.
llvm::FoldingSetNodeID ID; llvm::FoldingSetNodeID ID;
CGFunctionInfo::Profile(ID, CallingConvention, ResTy, CGFunctionInfo::Profile(ID, CC, NoReturn, ResTy,
ArgTys.begin(), ArgTys.end()); ArgTys.begin(), ArgTys.end());
void *InsertPos = 0; void *InsertPos = 0;
@ -195,7 +208,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
return *FI; return *FI;
// Construct the function info. // Construct the function info.
FI = new CGFunctionInfo(CallingConvention, ResTy, ArgTys); FI = new CGFunctionInfo(CC, NoReturn, ResTy, ArgTys);
FunctionInfos.InsertNode(FI, InsertPos); FunctionInfos.InsertNode(FI, InsertPos);
// Compute ABI information. // Compute ABI information.
@ -205,10 +218,12 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy,
} }
CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention,
bool _NoReturn,
QualType ResTy, QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys) const llvm::SmallVector<QualType, 16> &ArgTys)
: CallingConvention(_CallingConvention), : CallingConvention(_CallingConvention),
EffectiveCallingConvention(_CallingConvention) EffectiveCallingConvention(_CallingConvention),
NoReturn(_NoReturn)
{ {
NumArgs = ArgTys.size(); NumArgs = ArgTys.size();
Args = new ArgInfo[1 + NumArgs]; Args = new ArgInfo[1 + NumArgs];
@ -490,6 +505,9 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
CallingConv = FI.getEffectiveCallingConvention(); CallingConv = FI.getEffectiveCallingConvention();
if (FI.isNoReturn())
FuncAttrs |= llvm::Attribute::NoReturn;
// FIXME: handle sseregparm someday... // FIXME: handle sseregparm someday...
if (TargetDecl) { if (TargetDecl) {
if (TargetDecl->hasAttr<NoThrowAttr>()) if (TargetDecl->hasAttr<NoThrowAttr>())

Просмотреть файл

@ -69,6 +69,9 @@ namespace CodeGen {
/// depend on the ABI. /// depend on the ABI.
unsigned EffectiveCallingConvention; unsigned EffectiveCallingConvention;
/// Whether this function is noreturn.
bool NoReturn;
unsigned NumArgs; unsigned NumArgs;
ArgInfo *Args; ArgInfo *Args;
@ -77,6 +80,7 @@ namespace CodeGen {
typedef ArgInfo *arg_iterator; typedef ArgInfo *arg_iterator;
CGFunctionInfo(unsigned CallingConvention, CGFunctionInfo(unsigned CallingConvention,
bool NoReturn,
QualType ResTy, QualType ResTy,
const llvm::SmallVector<QualType, 16> &ArgTys); const llvm::SmallVector<QualType, 16> &ArgTys);
~CGFunctionInfo() { delete[] Args; } ~CGFunctionInfo() { delete[] Args; }
@ -88,6 +92,8 @@ namespace CodeGen {
unsigned arg_size() const { return NumArgs; } unsigned arg_size() const { return NumArgs; }
bool isNoReturn() const { return NoReturn; }
/// getCallingConvention - Return the user specified calling /// getCallingConvention - Return the user specified calling
/// convention. /// convention.
unsigned getCallingConvention() const { return CallingConvention; } unsigned getCallingConvention() const { return CallingConvention; }
@ -108,6 +114,7 @@ namespace CodeGen {
void Profile(llvm::FoldingSetNodeID &ID) { void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddInteger(getCallingConvention()); ID.AddInteger(getCallingConvention());
ID.AddBoolean(NoReturn);
getReturnType().Profile(ID); getReturnType().Profile(ID);
for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it)
it->type.Profile(ID); it->type.Profile(ID);
@ -115,10 +122,12 @@ namespace CodeGen {
template<class Iterator> template<class Iterator>
static void Profile(llvm::FoldingSetNodeID &ID, static void Profile(llvm::FoldingSetNodeID &ID,
unsigned CallingConvention, unsigned CallingConvention,
bool NoReturn,
QualType ResTy, QualType ResTy,
Iterator begin, Iterator begin,
Iterator end) { Iterator end) {
ID.AddInteger(CallingConvention); ID.AddInteger(CallingConvention);
ID.AddBoolean(NoReturn);
ResTy.Profile(ID); ResTy.Profile(ID);
for (; begin != end; ++begin) for (; begin != end; ++begin)
begin->Profile(ID); begin->Profile(ID);

Просмотреть файл

@ -327,9 +327,9 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
// Push the Src ptr. // Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src), CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType())); BaseCopyCtor->getParamDecl(0)->getType()));
QualType ResultType = const FunctionProtoType *FPT
BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); = BaseCopyCtor->getType()->getAs<FunctionProtoType>();
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
} }
EmitBlock(ContinueBlock); EmitBlock(ContinueBlock);
@ -412,8 +412,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
RValue::getAggregate(Src); RValue::getAggregate(Src);
CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, ReturnValueSlot(), CallArgs, MD); Callee, ReturnValueSlot(), CallArgs, MD);
} }
EmitBlock(ContinueBlock); EmitBlock(ContinueBlock);
@ -503,9 +502,9 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
// Push the Src ptr. // Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src), CallArgs.push_back(std::make_pair(RValue::get(Src),
BaseCopyCtor->getParamDecl(0)->getType())); BaseCopyCtor->getParamDecl(0)->getType()));
QualType ResultType = const FunctionProtoType *FPT =
BaseCopyCtor->getType()->getAs<FunctionType>()->getResultType(); BaseCopyCtor->getType()->getAs<FunctionProtoType>();
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs), EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor); Callee, ReturnValueSlot(), CallArgs, BaseCopyCtor);
} }
} }
@ -550,9 +549,7 @@ void CodeGenFunction::EmitClassCopyAssignment(
RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) : RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
RValue::getAggregate(Src); RValue::getAggregate(Src);
CallArgs.push_back(std::make_pair(SrcValue, SrcTy)); CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
QualType ResultType = EmitCall(CGM.getTypes().getFunctionInfo(CallArgs, FPT),
MD->getType()->getAs<FunctionType>()->getResultType();
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, ReturnValueSlot(), CallArgs, MD); Callee, ReturnValueSlot(), CallArgs, MD);
} }
@ -1197,7 +1194,8 @@ CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
llvm::SmallString<16> Name; llvm::SmallString<16> Name;
llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount); llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
QualType R = getContext().VoidTy; 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); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn = llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,

Просмотреть файл

@ -194,9 +194,9 @@ static void CopyObject(CodeGenFunction &CGF, const Expr *E,
// Push the Src ptr. // Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src), CallArgs.push_back(std::make_pair(RValue::get(Src),
CopyCtor->getParamDecl(0)->getType())); CopyCtor->getParamDecl(0)->getType()));
QualType ResultType = const FunctionProtoType *FPT
CopyCtor->getType()->getAs<FunctionType>()->getResultType(); = CopyCtor->getType()->getAs<FunctionProtoType>();
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, CopyCtor); Callee, ReturnValueSlot(), CallArgs, CopyCtor);
CGF.setInvokeDest(PrevLandingPad); CGF.setInvokeDest(PrevLandingPad);
} else } else
@ -244,9 +244,10 @@ static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
// Push the Src ptr. // Push the Src ptr.
CallArgs.push_back(std::make_pair(RValue::get(Src), CallArgs.push_back(std::make_pair(RValue::get(Src),
CopyCtor->getParamDecl(0)->getType())); CopyCtor->getParamDecl(0)->getType()));
QualType ResultType =
CopyCtor->getType()->getAs<FunctionType>()->getResultType(); const FunctionProtoType *FPT
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), = CopyCtor->getType()->getAs<FunctionProtoType>();
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
Callee, ReturnValueSlot(), CallArgs, CopyCtor); Callee, ReturnValueSlot(), CallArgs, CopyCtor);
} else } else
llvm_unreachable("uncopyable object"); llvm_unreachable("uncopyable object");

Просмотреть файл

@ -1853,14 +1853,6 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
return LValue::MakeAddr(RV.getAggregateAddr(), MakeQualifiers(E->getType())); 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, RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
ReturnValueSlot ReturnValue, ReturnValueSlot ReturnValue,
CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgBeg,
@ -1873,16 +1865,14 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, llvm::Value *Callee,
CalleeType = getContext().getCanonicalType(CalleeType); CalleeType = getContext().getCanonicalType(CalleeType);
QualType FnType = cast<PointerType>(CalleeType)->getPointeeType(); const FunctionType *FnType
QualType ResultType = cast<FunctionType>(FnType)->getResultType(); = cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType());
QualType ResultType = FnType->getResultType();
CallArgList Args; CallArgList Args;
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd); EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
unsigned CallingConvention = return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType),
ClangCallConvToLLVMCallConv(FnType->getAs<FunctionType>()->getCallConv());
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
CallingConvention),
Callee, ReturnValue, Args, TargetDecl); Callee, ReturnValue, Args, TargetDecl);
} }

Просмотреть файл

@ -42,8 +42,10 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
// And the rest of the call args // And the rest of the call args
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd); EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType(); QualType ResultType = FPT->getResultType();
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
FPT->getCallConv(),
FPT->getNoReturnAttr()), Callee,
ReturnValue, Args, MD); ReturnValue, Args, MD);
} }
@ -244,8 +246,8 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
// And the rest of the call args // And the rest of the call args
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType(); const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>();
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee, return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee,
ReturnValue, Args); ReturnValue, Args);
} }
@ -542,7 +544,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// Emit the call to new. // Emit the call to new.
RValue RV = RValue RV =
EmitCall(CGM.getTypes().getFunctionInfo(NewFTy->getResultType(), NewArgs), EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy),
CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD); CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD);
// If an allocation function is declared with an empty exception specification // 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)); DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
// Emit the call to delete. // Emit the call to delete.
EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(), EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy),
DeleteArgs),
CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(), CGM.GetAddrOfFunction(DeleteFD), ReturnValueSlot(),
DeleteArgs, DeleteFD); DeleteArgs, DeleteFD);
} }

Просмотреть файл

@ -190,7 +190,8 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy));
// FIXME: We shouldn't need to get the function info here, the // FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function. // 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); GetPropertyFn, ReturnValueSlot(), Args);
// We need to fix the type here. Ivars with copy & retain are // We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or // always objects so we don't need to worry about complex or
@ -278,7 +279,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
getContext().BoolTy)); getContext().BoolTy));
// FIXME: We shouldn't need to get the function info here, the runtime // FIXME: We shouldn't need to get the function info here, the runtime
// already should have computed it to build the function. // 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); ReturnValueSlot(), Args);
} else { } else {
// FIXME: Find a clean way to avoid AST node creation. // FIXME: Find a clean way to avoid AST node creation.
@ -554,7 +556,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
getContext().getObjCIdType())); getContext().getObjCIdType()));
// FIXME: We shouldn't need to get the function info here, the runtime already // FIXME: We shouldn't need to get the function info here, the runtime already
// should have computed it to build the function. // 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); EnumerationMutationFn, ReturnValueSlot(), Args2);
EmitBlock(WasNotMutated); EmitBlock(WasNotMutated);

Просмотреть файл

@ -464,7 +464,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes(); 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 = const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@ -571,7 +572,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes(); 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 = const llvm::FunctionType *impType =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false);
@ -1686,7 +1688,8 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
llvm::SmallVector<QualType,16> Params; llvm::SmallVector<QualType,16> Params;
Params.push_back(ASTIdTy); Params.push_back(ASTIdTy);
const llvm::FunctionType *FTy = 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"); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
} }

Просмотреть файл

@ -305,7 +305,8 @@ public:
Params.push_back(Ctx.LongTy); Params.push_back(Ctx.LongTy);
Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy = 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"); return CGM.CreateRuntimeFunction(FTy, "objc_getProperty");
} }
@ -323,7 +324,8 @@ public:
Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy);
Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy);
const llvm::FunctionType *FTy = 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"); return CGM.CreateRuntimeFunction(FTy, "objc_setProperty");
} }
@ -334,7 +336,8 @@ public:
llvm::SmallVector<QualType,16> Params; llvm::SmallVector<QualType,16> Params;
Params.push_back(Ctx.getObjCIdType()); Params.push_back(Ctx.getObjCIdType());
const llvm::FunctionType *FTy = 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"); return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
} }
@ -1554,7 +1557,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
CodeGenTypes &Types = CGM.getTypes(); 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 = const llvm::FunctionType *FTy =
Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); 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 // FIXME. This is too much work to get the ABI-specific result type needed to
// find the message name. // find the message name.
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType,
llvm::SmallVector<QualType, 16>()); llvm::SmallVector<QualType, 16>(),
CC_Default, false);
llvm::Constant *Fn = 0; llvm::Constant *Fn = 0;
std::string Name("\01l_"); std::string Name("\01l_");
if (CGM.ReturnTypeUsesSret(FnInfo)) { if (CGM.ReturnTypeUsesSret(FnInfo)) {
@ -5163,7 +5168,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
ActualArgs.push_back(std::make_pair(RValue::get(Arg1), ActualArgs.push_back(std::make_pair(RValue::get(Arg1),
ObjCTypes.MessageRefCPtrTy)); ObjCTypes.MessageRefCPtrTy));
ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); 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); llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0);
Callee = CGF.Builder.CreateLoad(Callee); Callee = CGF.Builder.CreateLoad(Callee);
const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true); const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true);

Просмотреть файл

@ -196,7 +196,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
} }
// FIXME: Leaked. // 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()) { if (RetTy->isVoidType()) {
// Void type; nothing to return. // Void type; nothing to return.

Просмотреть файл

@ -198,6 +198,12 @@ public:
const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D, const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D,
CXXDtorType Type); 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. // getFunctionInfo - Get the function info for a member function.
const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD, const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP); const FunctionProtoType *FTP);
@ -207,13 +213,16 @@ public:
/// specified, the "C" calling convention will be used. /// specified, the "C" calling convention will be used.
const CGFunctionInfo &getFunctionInfo(QualType ResTy, const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const CallArgList &Args, const CallArgList &Args,
unsigned CallingConvention = 0); CallingConv CC,
bool NoReturn);
const CGFunctionInfo &getFunctionInfo(QualType ResTy, const CGFunctionInfo &getFunctionInfo(QualType ResTy,
const FunctionArgList &Args, const FunctionArgList &Args,
unsigned CallingConvention = 0); CallingConv CC,
bool NoReturn);
const CGFunctionInfo &getFunctionInfo(QualType RetTy, const CGFunctionInfo &getFunctionInfo(QualType RetTy,
const llvm::SmallVector<QualType, 16> &ArgTys, const llvm::SmallVector<QualType, 16> &ArgTys,
unsigned CallingConvention = 0); CallingConv CC,
bool NoReturn);
public: // These are internal details of CGT that shouldn't be used externally. public: // These are internal details of CGT that shouldn't be used externally.
/// addFieldInfo - Assign field number to field FD. /// addFieldInfo - Assign field number to field FD.

Просмотреть файл

@ -559,10 +559,8 @@ public:
//===--------------------------------------------------------------------===// //===--------------------------------------------------------------------===//
// Type Analysis / Processing: SemaType.cpp. // Type Analysis / Processing: SemaType.cpp.
// //
QualType adjustParameterType(QualType T); QualType adjustParameterType(QualType T);
void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL,
bool HandleCallConvAttributes = false,
bool HandleOnlyCallConv = false);
QualType BuildPointerType(QualType T, unsigned Quals, QualType BuildPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity); SourceLocation Loc, DeclarationName Entity);
QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals, QualType BuildReferenceType(QualType T, bool LValueRef, unsigned Quals,

Просмотреть файл

@ -2500,7 +2500,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
return; return;
if (FD->getResultType()->isVoidType()) if (FD->getResultType()->isVoidType())
ReturnsVoid = true; ReturnsVoid = true;
if (FD->hasAttr<NoReturnAttr>()) if (FD->hasAttr<NoReturnAttr>() ||
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
HasNoReturn = true; HasNoReturn = true;
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (MD->getResultType()->isVoidType()) if (MD->getResultType()->isVoidType())

Просмотреть файл

@ -908,14 +908,6 @@ static Sema::CXXSpecialMember getSpecialMember(ASTContext &Ctx,
return Sema::CXXCopyAssignment; 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 /// MergeFunctionDecl - We just parsed a function 'New' from
/// declarator D which has the same name and scope as a previous /// declarator D which has the same name and scope as a previous
/// declaration 'Old'. Figure out how to resolve this situation, /// 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()); NewQType = Context.getCallConvType(NewQType, OldType->getCallConv());
New->setType(NewQType); New->setType(NewQType);
NewQType = Context.getCanonicalType(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. // Calling conventions really aren't compatible, so complain.
Diag(New->getLocation(), diag::err_attributes_are_not_compatible) Diag(New->getLocation(), diag::err_cconv_change)
<< getCallConvName(NewType->getCallConv()) << FunctionType::getNameForCallConv(NewType->getCallConv())
<< getCallConvName(OldType->getCallConv()); << (OldType->getCallConv() == CC_Default)
<< (OldType->getCallConv() == CC_Default ? "" :
FunctionType::getNameForCallConv(OldType->getCallConv()));
Diag(Old->getLocation(), diag::note_previous_declaration);
return true; 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) { if (getLangOptions().CPlusPlus) {
// (C++98 13.1p2): // (C++98 13.1p2):
// Certain function declarations cannot be overloaded: // Certain function declarations cannot be overloaded:
@ -4383,7 +4386,7 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
} }
if (Context.BuiltinInfo.isNoReturn(BuiltinID)) if (Context.BuiltinInfo.isNoReturn(BuiltinID))
FD->addAttr(::new (Context) NoReturnAttr()); FD->setType(Context.getNoReturnType(FD->getType()));
if (Context.BuiltinInfo.isNoThrow(BuiltinID)) if (Context.BuiltinInfo.isNoThrow(BuiltinID))
FD->addAttr(::new (Context) NoThrowAttr()); FD->addAttr(::new (Context) NoThrowAttr());
if (Context.BuiltinInfo.isConst(BuiltinID)) if (Context.BuiltinInfo.isConst(BuiltinID))

Просмотреть файл

@ -391,6 +391,11 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
} }
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { 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<ValueDecl>(d))
return;
if (HandleCommonNoReturnAttr(d, Attr, S)) if (HandleCommonNoReturnAttr(d, Attr, S))
d->addAttr(::new (S.Context) NoReturnAttr()); 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) { static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) {
if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) { if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) {
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) 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; return;
} }
// FIXME: Actually store the attribute on the declaration // 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())); 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<ValueDecl>(d);
if (VD && VD->getType()->isFunctionPointerType())
return;
if (!isa<FunctionDecl>(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<FastCallAttr>()) {
S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible)
<< "cdecl" << "fastcall";
return;
}
// cdecl and stdcall attributes are mutually incompatible.
if (d->getAttr<StdCallAttr>()) {
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<ValueDecl>(d);
if (VD && VD->getType()->isFunctionPointerType())
return;
if (!isa<FunctionDecl>(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<FastCallAttr>()) {
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<FunctionProtoType>();
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<ValueDecl>(d);
if (VD && VD->getType()->isFunctionPointerType())
return;
if (!isa<FunctionDecl>(d)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
<< Attr.getName() << 0 /*function*/;
return;
}
DiagnoseCConv(cast<FunctionDecl>(d), "fastcall", Attr.getLoc(), S);
// stdcall and fastcall attributes are mutually incompatible.
if (d->getAttr<StdCallAttr>()) {
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) { static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) {
// check the attribute arguments. // 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_base_check: HandleBaseCheckAttr (D, Attr, S); break;
case AttributeList::AT_carries_dependency: case AttributeList::AT_carries_dependency:
HandleDependencyAttr (D, Attr, S); break; 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_constructor: HandleConstructorAttr (D, Attr, S); break;
case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break; case AttributeList::AT_deprecated: HandleDeprecatedAttr (D, Attr, S); break;
case AttributeList::AT_destructor: HandleDestructorAttr (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: case AttributeList::AT_ext_vector_type:
HandleExtVectorTypeAttr(scope, D, Attr, S); HandleExtVectorTypeAttr(scope, D, Attr, S);
break; break;
case AttributeList::AT_fastcall: HandleFastCallAttr (D, Attr, S); break;
case AttributeList::AT_final: HandleFinalAttr (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: HandleFormatAttr (D, Attr, S); break;
case AttributeList::AT_format_arg: HandleFormatArgAttr (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_packed: HandlePackedAttr (D, Attr, S); break;
case AttributeList::AT_section: HandleSectionAttr (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_unavailable: HandleUnavailableAttr (D, Attr, S); break;
case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break;
case AttributeList::AT_used: HandleUsedAttr (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. case AttributeList::AT_no_instrument_function: // Interacts with -pg.
// Just ignore // Just ignore
break; break;
case AttributeList::AT_stdcall:
case AttributeList::AT_cdecl:
case AttributeList::AT_fastcall:
// These are all treated as type attributes.
break;
default: default:
// Ask target about the attribute. // Ask target about the attribute.
const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema();

Просмотреть файл

@ -1043,7 +1043,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
QualType FnRetType; QualType FnRetType;
if (const FunctionDecl *FD = getCurFunctionDecl()) { if (const FunctionDecl *FD = getCurFunctionDecl()) {
FnRetType = FD->getResultType(); FnRetType = FD->getResultType();
if (FD->hasAttr<NoReturnAttr>()) if (FD->hasAttr<NoReturnAttr>() ||
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
<< getCurFunctionOrMethodDecl()->getDeclName(); << getCurFunctionOrMethodDecl()->getDeclName();
} else if (ObjCMethodDecl *MD = getCurMethodDecl()) } else if (ObjCMethodDecl *MD = getCurMethodDecl())

Просмотреть файл

@ -68,12 +68,41 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
return false; return false;
} }
typedef std::pair<const AttributeList*,QualType> DelayedAttribute;
typedef llvm::SmallVectorImpl<DelayedAttribute> 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 /// \brief Convert the specified declspec to the appropriate type
/// object. /// object.
/// \param D the declarator containing the declaration specifier. /// \param D the declarator containing the declaration specifier.
/// \returns The type described by the declaration specifiers. This function /// \returns The type described by the declaration specifiers. This function
/// never returns null. /// 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 // FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking. // checking.
const DeclSpec &DS = TheDeclarator.getDeclSpec(); 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 // See if there are any attributes on the declspec that apply to the type (as
// opposed to the decl). // opposed to the decl).
if (const AttributeList *AL = DS.getAttributes()) if (const AttributeList *AL = DS.getAttributes())
TheSema.ProcessTypeAttributeList(Result, AL); ProcessTypeAttributeList(TheSema, Result, AL, Delayed);
// Apply const/volatile/restrict qualifiers to T. // Apply const/volatile/restrict qualifiers to T.
if (unsigned TypeQuals = DS.getTypeQualifiers()) { if (unsigned TypeQuals = DS.getTypeQualifiers()) {
@ -890,12 +919,14 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
// have a type. // have a type.
QualType T; QualType T;
llvm::SmallVector<DelayedAttribute,4> FnAttrsFromDeclSpec;
switch (D.getName().getKind()) { switch (D.getName().getKind()) {
case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_Identifier:
case UnqualifiedId::IK_OperatorFunctionId: case UnqualifiedId::IK_OperatorFunctionId:
case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_LiteralOperatorId:
case UnqualifiedId::IK_TemplateId: case UnqualifiedId::IK_TemplateId:
T = ConvertDeclSpecToType(D, *this); T = ConvertDeclSpecToType(*this, D, FnAttrsFromDeclSpec);
if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned()) if (!D.isInvalidType() && OwnedDecl && D.getDeclSpec().isTypeSpecOwned())
*OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep()); *OwnedDecl = cast<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
@ -967,6 +998,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
if (D.getIdentifier()) if (D.getIdentifier())
Name = D.getIdentifier(); Name = D.getIdentifier();
llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk;
// Walk the DeclTypeInfo, building the recursive type as we go. // Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is // DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :). // opposite of what we want :).
@ -1186,6 +1219,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
FTI.hasAnyExceptionSpec, FTI.hasAnyExceptionSpec,
Exceptions.size(), Exceptions.data()); 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; break;
} }
case DeclaratorChunk::MemberPointer: case DeclaratorChunk::MemberPointer:
@ -1244,9 +1284,11 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
T = Context.IntTy; T = Context.IntTy;
} }
DiagnoseDelayedFnAttrs(*this, FnAttrsFromPreviousChunk);
// See if there are any attributes on this declarator chunk. // See if there are any attributes on this declarator chunk.
if (const AttributeList *AL = DeclType.getAttrs()) if (const AttributeList *AL = DeclType.getAttrs())
ProcessTypeAttributeList(T, AL, true); ProcessTypeAttributeList(*this, T, AL, FnAttrsFromPreviousChunk);
} }
if (getLangOptions().CPlusPlus && T->isFunctionType()) { 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 // Process any function attributes we might have delayed from the
// type, apply the type attribute to the type!) // declaration-specifiers.
if (const AttributeList *Attrs = D.getAttributes()) ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec);
ProcessTypeAttributeList(T, Attrs, true);
// Also look in the decl spec. // If there were any type attributes applied to the decl itself, not
if (const AttributeList *Attrs = D.getDeclSpec().getAttributes()) // the type, apply them to the result type. But don't do this for
ProcessTypeAttributeList(T, Attrs, true, true); // 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 (TInfo) {
if (D.isInvalidType()) if (D.isInvalidType())
@ -1620,36 +1667,6 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type,
Type = S.Context.getAddrSpaceQualType(Type, ASIdx); 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 /// HandleObjCGCTypeAttribute - Process an objc's gc attribute on the
/// specified type. The attribute contains 1 argument, weak or strong. /// specified type. The attribute contains 1 argument, weak or strong.
static void HandleObjCGCTypeAttribute(QualType &Type, static void HandleObjCGCTypeAttribute(QualType &Type,
@ -1683,35 +1700,79 @@ static void HandleObjCGCTypeAttribute(QualType &Type,
Type = S.Context.getObjCGCQualType(Type, GCAttr); Type = S.Context.getObjCGCQualType(Type, GCAttr);
} }
/// HandleNoReturnTypeAttribute - Process the noreturn attribute on the /// Process an individual function attribute. Returns true if the
/// specified type. The attribute contains 0 arguments. /// attribute does not make sense to apply to this type.
static void HandleNoReturnTypeAttribute(QualType &Type, bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) {
const AttributeList &Attr, Sema &S) { if (Attr.getKind() == AttributeList::AT_noreturn) {
if (Attr.getNumArgs() != 0) // Complain immediately if the arg count is wrong.
return; 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. // Delay if this is not a function or pointer to block.
if (!Type->isFunctionPointerType() if (!Type->isFunctionPointerType()
&& !Type->isBlockPointerType() && !Type->isBlockPointerType()
&& !Type->isFunctionType()) && !Type->isFunctionType())
return; 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 // Otherwise, a calling convention.
/// specified type. The attribute contains 0 arguments. if (Attr.getNumArgs() != 0) {
static void HandleStdCallTypeAttribute(QualType &Type, S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
const AttributeList &Attr, Sema &S) { return false;
if (Attr.getNumArgs() != 0) }
return;
// We only apply this to a pointer to function. QualType T = Type;
if (!Type->isFunctionPointerType() if (const PointerType *PT = Type->getAs<PointerType>())
&& !Type->isFunctionType()) T = PT->getPointeeType();
return; const FunctionType *Fn = T->getAs<FunctionType>();
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<FunctionNoProtoType>(Fn)) {
S.Diag(Attr.getLoc(), diag::err_cconv_knr)
<< FunctionType::getNameForCallConv(CC);
return false;
}
const FunctionProtoType *FnP = cast<FunctionProtoType>(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 /// 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); CurType = S.Context.getVectorType(CurType, vectorSize/typeSize, false, false);
} }
void Sema::ProcessTypeAttributeList(QualType &Result, const AttributeList *AL, void ProcessTypeAttributeList(Sema &S, QualType &Result,
bool HandleCallConvAttributes, const AttributeList *AL,
bool HandleOnlyCallConv) { DelayedAttributeSet &FnAttrs) {
if(HandleOnlyCallConv)
assert(HandleCallConvAttributes && "Can't not handle call-conv attributes"
" while only handling them!");
// Scan through and apply attributes to this type where it makes sense. Some // Scan through and apply attributes to this type where it makes sense. Some
// attributes (such as __address_space__, __vector_size__, etc) apply to the // attributes (such as __address_space__, __vector_size__, etc) apply to the
// type, but others can be present in the type specifiers even though they // 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. // the LeftOverAttrs list for rechaining.
switch (AL->getKind()) { switch (AL->getKind()) {
default: break; default: break;
case AttributeList::AT_address_space: case AttributeList::AT_address_space:
if (!HandleOnlyCallConv) HandleAddressSpaceTypeAttribute(Result, *AL, S);
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);
break; break;
case AttributeList::AT_objc_gc: case AttributeList::AT_objc_gc:
if (!HandleOnlyCallConv) HandleObjCGCTypeAttribute(Result, *AL, S);
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);
break; break;
case AttributeList::AT_vector_size: case AttributeList::AT_vector_size:
if (!HandleOnlyCallConv) HandleVectorSizeAttr(Result, *AL, S);
HandleVectorSizeAttr(Result, *AL, *this); 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; break;
} }
} }

Просмотреть файл

@ -74,3 +74,10 @@ int t19(void) {
void t20(void) { void t20(void) {
__builtin_abort(); __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)

Просмотреть файл

@ -24,10 +24,10 @@ int main(void) {
// CHECK: call x86_fastcallcc void @f3() // CHECK: call x86_fastcallcc void @f3()
// CHECK: call x86_stdcallcc void @f4() // CHECK: call x86_stdcallcc void @f4()
pf1(); pf2(); pf3(); pf4(); pf1(); pf2(); pf3(); pf4();
// CHECK: call x86_fastcallcc void %tmp() // CHECK: call x86_fastcallcc void %{{.*}}()
// CHECK: call x86_stdcallcc void %tmp1() // CHECK: call x86_stdcallcc void %{{.*}}()
// CHECK: call x86_fastcallcc void %tmp2() // CHECK: call x86_fastcallcc void %{{.*}}()
// CHECK: call x86_stdcallcc void %tmp3() // CHECK: call x86_stdcallcc void %{{.*}}()
return 0; return 0;
} }

Просмотреть файл

@ -11,7 +11,7 @@ static void __attribute__((noreturn)) f0(void) {
// On K&R // On K&R
int f1() __attribute__((noreturn)); 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)}} int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute requires 0 argument(s)}}

Просмотреть файл

@ -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(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)) 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() {} void __attribute__((cdecl)) ctest0() {}
@ -33,3 +33,6 @@ void (*pctest0)() = ctest0;
void ctest2() {} void ctest2() {}
void (__attribute__((cdecl)) *pctest2)() = ctest2; void (__attribute__((cdecl)) *pctest2)() = ctest2;
typedef void (__attribute__((fastcall)) *Handler) (float *);
Handler H = foo;

Просмотреть файл

@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify %s
// CC qualifier can be applied only to functions // CC qualifier can be applied only to functions
int __attribute__((stdcall)) var1; // expected-warning{{'stdcall' 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' attribute only applies to function types}} int __attribute__((fastcall)) var2; // expected-warning{{'fastcall' only applies to function types; type here is 'int'}}
// Different CC qualifiers are not compatible // Different CC qualifiers are not compatible
void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{stdcall and fastcall attributes are not compatible}} void __attribute__((stdcall, fastcall)) foo3(void); // expected-error{{stdcall and fastcall attributes are not compatible}}
void __attribute__((stdcall)) foo4(); void __attribute__((stdcall)) foo4(); // expected-note{{previous declaration is here}}
void __attribute__((fastcall)) foo4(void); // expected-error{{fastcall and stdcall attributes are not compatible}} void __attribute__((fastcall)) foo4(void); // expected-error{{function declared 'fastcall' here was previously declared 'stdcall'}}