зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
e50187a987
Коммит
04a67a6aa3
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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">,
|
||||
|
|
|
@ -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<QualType, 16> 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<FunctionType>();
|
||||
const FunctionType *rbase = rhs->getAs<FunctionType>();
|
||||
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -496,10 +496,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
|
|||
// Load the function.
|
||||
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 =
|
||||
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<FunctionProtoType>(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);
|
||||
|
|
|
@ -165,7 +165,8 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
|
|||
GlobalDecl GD, bool Extern,
|
||||
const CovariantThunkAdjustment &Adjustment) {
|
||||
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;
|
||||
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<FunctionProtoType>();
|
||||
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()
|
||||
|
|
|
@ -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<QualType, 16>(), 0);
|
||||
llvm::SmallVector<QualType, 16>(),
|
||||
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<StdCallAttr>())
|
||||
return llvm::CallingConv::X86_StdCall;
|
||||
return CC_X86StdCall;
|
||||
|
||||
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,
|
||||
|
@ -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<FunctionProtoType>();
|
||||
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<FunctionProtoType>();
|
||||
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<FunctionProtoType>();
|
||||
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<FunctionType>();
|
||||
if (const FunctionNoProtoType *FNTP = dyn_cast<FunctionNoProtoType>(FTy))
|
||||
return getFunctionInfo(FNTP->getResultType(),
|
||||
llvm::SmallVector<QualType, 16>(),
|
||||
CallingConvention);
|
||||
FNTP->getCallConv(), FNTP->getNoReturnAttr());
|
||||
|
||||
const FunctionProtoType *FPT = cast<FunctionProtoType>(FTy);
|
||||
llvm::SmallVector<QualType, 16> 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<QualType, 16> 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<QualType, 16> 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<QualType, 16> &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<QualType, 16> &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<NoThrowAttr>())
|
||||
|
|
|
@ -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<QualType, 16> &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<class Iterator>
|
||||
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);
|
||||
|
|
|
@ -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<FunctionType>()->getResultType();
|
||||
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
|
||||
const FunctionProtoType *FPT
|
||||
= BaseCopyCtor->getType()->getAs<FunctionProtoType>();
|
||||
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<FunctionType>()->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<FunctionType>()->getResultType();
|
||||
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
|
||||
const FunctionProtoType *FPT =
|
||||
BaseCopyCtor->getType()->getAs<FunctionProtoType>();
|
||||
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<FunctionType>()->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,
|
||||
|
|
|
@ -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<FunctionType>()->getResultType();
|
||||
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
|
||||
const FunctionProtoType *FPT
|
||||
= CopyCtor->getType()->getAs<FunctionProtoType>();
|
||||
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<FunctionType>()->getResultType();
|
||||
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
|
||||
|
||||
const FunctionProtoType *FPT
|
||||
= CopyCtor->getType()->getAs<FunctionProtoType>();
|
||||
CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(CallArgs, FPT),
|
||||
Callee, ReturnValueSlot(), CallArgs, CopyCtor);
|
||||
} else
|
||||
llvm_unreachable("uncopyable object");
|
||||
|
|
|
@ -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<PointerType>(CalleeType)->getPointeeType();
|
||||
QualType ResultType = cast<FunctionType>(FnType)->getResultType();
|
||||
const FunctionType *FnType
|
||||
= cast<FunctionType>(cast<PointerType>(CalleeType)->getPointeeType());
|
||||
QualType ResultType = FnType->getResultType();
|
||||
|
||||
CallArgList Args;
|
||||
EmitCallArgs(Args, dyn_cast<FunctionProtoType>(FnType), ArgBeg, ArgEnd);
|
||||
|
||||
unsigned CallingConvention =
|
||||
ClangCallConvToLLVMCallConv(FnType->getAs<FunctionType>()->getCallConv());
|
||||
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
|
||||
CallingConvention),
|
||||
return EmitCall(CGM.getTypes().getFunctionInfo(Args, FnType),
|
||||
Callee, ReturnValue, Args, TargetDecl);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<FunctionType>()->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<FunctionType>()->getResultType();
|
||||
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
|
||||
const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>();
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<QualType,16> 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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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<QualType,16> 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<QualType, 16>());
|
||||
llvm::SmallVector<QualType, 16>(),
|
||||
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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<QualType, 16> &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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -2500,7 +2500,8 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
|
|||
return;
|
||||
if (FD->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (FD->hasAttr<NoReturnAttr>())
|
||||
if (FD->hasAttr<NoReturnAttr>() ||
|
||||
FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
|
||||
HasNoReturn = true;
|
||||
} else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
|
||||
if (MD->getResultType()->isVoidType())
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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<ValueDecl>(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<ParmVarDecl>(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<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) {
|
||||
// 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();
|
||||
|
|
|
@ -1043,7 +1043,8 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, ExprArg rex) {
|
|||
QualType FnRetType;
|
||||
if (const FunctionDecl *FD = getCurFunctionDecl()) {
|
||||
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)
|
||||
<< getCurFunctionOrMethodDecl()->getDeclName();
|
||||
} else if (ObjCMethodDecl *MD = getCurMethodDecl())
|
||||
|
|
|
@ -68,12 +68,41 @@ static bool isOmittedBlockReturnType(const Declarator &D) {
|
|||
return false;
|
||||
}
|
||||
|
||||
typedef std::pair<const AttributeList*,QualType> DelayedAttribute;
|
||||
typedef llvm::SmallVectorImpl<DelayedAttribute> DelayedAttributeSet;
|
||||
|
||||
static void ProcessTypeAttributeList(Sema &S, QualType &Type,
|
||||
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<DelayedAttribute,4> 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<TagDecl>((Decl *)D.getDeclSpec().getTypeRep());
|
||||
|
@ -967,6 +998,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
|
|||
if (D.getIdentifier())
|
||||
Name = D.getIdentifier();
|
||||
|
||||
llvm::SmallVector<DelayedAttribute,4> FnAttrsFromPreviousChunk;
|
||||
|
||||
// Walk the DeclTypeInfo, building the recursive type as we go.
|
||||
// DeclTypeInfos are ordered from the identifier out, which is
|
||||
// opposite of what we want :).
|
||||
|
@ -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<PointerType>())
|
||||
T = PT->getPointeeType();
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)}}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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'}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче