Delete CC_Default and use the target default CC everywhere

Summary:
Makes functions with implicit calling convention compatible with
function types with a matching explicit calling convention.  This fixes
things like calls to qsort(), which has an explicit __cdecl attribute on
the comparator in Windows headers.

Clang will now infer the calling convention from the declarator.  There
are two cases when the CC must be adjusted during redeclaration:
1. When defining a non-inline static method.
2. When redeclaring a function with an implicit or mismatched
convention.

Fixes PR13457, and allows clang to compile CommandLine.cpp for the
Microsoft C++ ABI.

Excellent test cases provided by Alexander Zinenko!

Reviewers: rsmith

Differential Revision: http://llvm-reviews.chandlerc.com/D1231

llvm-svn: 189412
This commit is contained in:
Reid Kleckner 2013-08-27 23:08:25 +00:00
parent 8f4524a728
commit 78af0708b7
26 changed files with 755 additions and 227 deletions

View File

@ -1769,19 +1769,9 @@ public:
NestedNameSpecifier *
getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const;
/// \brief Retrieves the default calling convention to use for
/// C++ instance methods.
CallingConv getDefaultCXXMethodCallConv(bool isVariadic);
/// \brief Retrieves the canonical representation of the given
/// calling convention.
CallingConv getCanonicalCallConv(CallingConv CC) const;
/// \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 default calling convention for the current target.
CallingConv getDefaultCallingConvention(bool isVariadic,
bool IsCXXMethod) const;
/// \brief Retrieves the "canonical" template name that refers to a
/// given template.

View File

@ -1812,6 +1812,10 @@ template <> const TypedefType *Type::getAs() const;
/// non-sugared type.
template <> const TemplateSpecializationType *Type::getAs() const;
/// \brief This will check for an AttributedType by removing any existing sugar
/// until it reaches an AttributedType or a non-sugared type.
template <> const AttributedType *Type::getAs() const;
// We can do canonical leaf types faster, because we don't have to
// worry about preserving child type decoration.
#define TYPE(Class, Base)
@ -2683,7 +2687,11 @@ class FunctionType : public Type {
// Constructor with all defaults. Use when for example creating a
// function know to use defaults.
ExtInfo() : Bits(0) {}
ExtInfo() : Bits(CC_C) { }
// Constructor with just the calling convention, which is an important part
// of the canonical type.
ExtInfo(CallingConv CC) : Bits(CC) { }
bool getNoReturn() const { return Bits & NoReturnMask; }
bool getProducesResult() const { return Bits & ProducesResultMask; }
@ -2826,6 +2834,12 @@ public:
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
ConsumedArguments(0) {}
ExtProtoInfo(CallingConv CC)
: ExtInfo(CC), Variadic(false), HasTrailingReturn(false), TypeQuals(0),
ExceptionSpecType(EST_None), RefQualifier(RQ_None), NumExceptions(0),
Exceptions(0), NoexceptExpr(0), ExceptionSpecDecl(0),
ExceptionSpecTemplate(0), ConsumedArguments(0) {}
FunctionType::ExtInfo ExtInfo;
bool Variadic : 1;
bool HasTrailingReturn : 1;

View File

@ -200,7 +200,6 @@ namespace clang {
/// \brief CallingConv - Specifies the calling convention that a function uses.
enum CallingConv {
CC_Default,
CC_C, // __attribute__((cdecl))
CC_X86StdCall, // __attribute__((stdcall))
CC_X86FastCall, // __attribute__((fastcall))

View File

@ -779,7 +779,6 @@ public:
default:
return CCCR_Warning;
case CC_C:
case CC_Default:
return CCCR_OK;
}
}

View File

@ -2539,6 +2539,15 @@ public:
bool CheckNoReturnAttr(const AttributeList &attr);
void CheckAlignasUnderalignment(Decl *D);
/// Adjust the calling convention of a method to be the ABI default if it
/// wasn't specified explicitly. This handles method types formed from
/// function type typedefs and typename template arguments.
void adjustMemberFunctionCC(QualType &T);
/// Get the outermost AttributedType node that sets a calling convention.
/// Valid types should not have multiple attributes with different CCs.
const AttributedType *getCallingConvAttributedType(QualType T) const;
/// \brief Stmt attributes - this routine is the top level dispatcher.
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
SourceRange Range);

View File

@ -2732,9 +2732,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
QualType
ASTContext::getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const {
const CallingConv DefaultCC = Info.getCC();
const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
CC_X86StdCall : DefaultCC;
const CallingConv CallConv = Info.getCC();
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@ -2746,11 +2745,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
return QualType(FT, 0);
QualType Canonical;
if (!ResultTy.isCanonical() ||
getCanonicalCallConv(CallConv) != CallConv) {
Canonical =
getFunctionNoProtoType(getCanonicalType(ResultTy),
Info.withCallingConv(getCanonicalCallConv(CallConv)));
if (!ResultTy.isCanonical()) {
Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info);
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@ -2799,14 +2795,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
const CallingConv DefaultCC = EPI.ExtInfo.getCC();
const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
CC_X86StdCall : DefaultCC;
// 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 || getCanonicalCallConv(CallConv) != CallConv) {
if (!isCanonical) {
SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@ -2816,8 +2808,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
CanonicalEPI.HasTrailingReturn = false;
CanonicalEPI.ExceptionSpecType = EST_None;
CanonicalEPI.NumExceptions = 0;
CanonicalEPI.ExtInfo
= CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
// Result types do not have ARC lifetime qualifiers.
QualType CanResultTy = getCanonicalType(ResultTy);
@ -2859,7 +2849,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
@ -6939,7 +6928,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
// Compatible functions must have compatible calling conventions
if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC()))
if (lbaseInfo.getCC() != rbaseInfo.getCC())
return QualType();
// Regparm is part of the calling convention.
@ -7784,7 +7773,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
"'.' should only occur at end of builtin type list!");
FunctionType::ExtInfo EI;
FunctionType::ExtInfo EI(CC_C);
if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true);
bool Variadic = (TypeStr[0] == '.');
@ -7955,16 +7944,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
}
CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
bool IsCXXMethod) const {
// Pass through to the C++ ABI object
return ABI->getDefaultMethodCallConv(isVariadic);
}
if (IsCXXMethod)
return ABI->getDefaultMethodCallConv(IsVariadic);
CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
if (CC == CC_C && !LangOpts.MRTD &&
getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
return CC_Default;
return CC;
return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C;
}
bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {

View File

@ -915,7 +915,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
void setCallingConv(CallingConv CC) {
switch (CC) {
case CC_Default: return;
case CC_C: return set("cc", "cdecl");
case CC_X86FastCall: return set("cc", "x86_fastcall");
case CC_X86StdCall: return set("cc", "x86_stdcall");

View File

@ -196,8 +196,10 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(Context.VoidTy, None,
FunctionProtoType::ExtProtoInfo())),
Context.getPointerType(Context.getFunctionType(
Context.VoidTy, None,
FunctionProtoType::ExtProtoInfo(
Context.getDefaultCallingConvention(false, true)))),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&

View File

@ -1391,20 +1391,9 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
// that they could be in a DLL and somebody from another module could call
// them.)
CallingConv CC = T->getCallConv();
if (CC == CC_Default) {
if (IsInstMethod) {
const FunctionProtoType *FPT =
T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>();
bool isVariadic = FPT->isVariadic();
CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
} else {
CC = CC_C;
}
}
switch (CC) {
default:
llvm_unreachable("Unsupported CC for mangling");
case CC_Default:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
case CC_X86ThisCall: Out << 'E'; break;

View File

@ -338,6 +338,10 @@ template <> const TemplateSpecializationType *Type::getAs() const {
return getAsSugar<TemplateSpecializationType>(this);
}
template <> const AttributedType *Type::getAs() const {
return getAsSugar<AttributedType>(this);
}
/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic
/// sugar off the given type. This should produce an object of the
/// same dynamic type as the canonical type.
@ -1559,9 +1563,6 @@ QualType QualType::getNonLValueExprType(const ASTContext &Context) const {
StringRef FunctionType::getNameForCallConv(CallingConv CC) {
switch (CC) {
case CC_Default:
llvm_unreachable("no name for default cc");
case CC_C: return "cdecl";
case CC_X86StdCall: return "stdcall";
case CC_X86FastCall: return "fastcall";

View File

@ -634,9 +634,14 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
if (!InsideCCAttribute) {
switch (Info.getCC()) {
case CC_Default: break;
case CC_C:
OS << " __attribute__((cdecl))";
// The C calling convention is the default on the vast majority of platforms
// we support. If the user wrote it explicitly, it will usually be printed
// while traversing the AttributedType. If the type has been desugared, let
// the canonical spelling be the implicit calling convention.
// FIXME: It would be better to be explicit in certain contexts, such as a
// cdecl function typedef used to declare a member function with the
// Microsoft C++ ABI.
break;
case CC_X86StdCall:
OS << " __attribute__((stdcall))";
@ -1152,6 +1157,8 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
}
case AttributedType::attr_regparm: {
// FIXME: When Sema learns to form this AttributedType, avoid printing the
// attribute again in printFunctionProtoAfter.
OS << "regparm(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
@ -1191,13 +1198,17 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
// FIXME: When Sema learns to form this AttributedType, avoid printing the
// attribute again in printFunctionProtoAfter.
case AttributedType::attr_noreturn: OS << "noreturn"; break;
case AttributedType::attr_cdecl: OS << "cdecl"; break;
case AttributedType::attr_fastcall: OS << "fastcall"; break;
case AttributedType::attr_stdcall: OS << "stdcall"; break;
case AttributedType::attr_thiscall: OS << "thiscall"; break;
case AttributedType::attr_pascal: OS << "pascal"; break;
case AttributedType::attr_pcs: {
case AttributedType::attr_pcs:
case AttributedType::attr_pcs_vfp: {
OS << "pcs(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())

View File

@ -3094,9 +3094,7 @@ public:
}
virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const {
return (CC == CC_Default ||
CC == CC_C ||
CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
return (CC == CC_C || CC == CC_IntelOclBicc) ? CCCR_OK : CCCR_Warning;
}
virtual CallingConv getDefaultCallingConv(CallingConvMethodType MT) const {

View File

@ -103,24 +103,12 @@ static const CGFunctionInfo &arrangeFreeFunctionType(CodeGenTypes &CGT,
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, FTP->getExtInfo());
}
/// Given the formal ext-info of a C++ instance method, adjust it
/// according to the C++ ABI in effect.
static void adjustCXXMethodInfo(CodeGenTypes &CGT,
FunctionType::ExtInfo &extInfo,
bool isVariadic) {
if (extInfo.getCC() == CC_Default) {
CallingConv CC = CGT.getContext().getDefaultCXXMethodCallConv(isVariadic);
extInfo = extInfo.withCallingConv(CC);
}
}
/// Arrange the argument and result information for a free function (i.e.
/// not a C++ or ObjC instance method) of the given type.
static const CGFunctionInfo &arrangeCXXMethodType(CodeGenTypes &CGT,
SmallVectorImpl<CanQualType> &prefix,
CanQual<FunctionProtoType> FTP) {
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
adjustCXXMethodInfo(CGT, extInfo, FTP->isVariadic());
return arrangeLLVMFunctionInfo(CGT, prefix, FTP, extInfo);
}
@ -223,7 +211,6 @@ CodeGenTypes::arrangeCXXConstructorDeclaration(const CXXConstructorDecl *D,
argTypes.push_back(FTP->getArgType(i));
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
adjustCXXMethodInfo(*this, extInfo, FTP->isVariadic());
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo, required);
}
@ -247,7 +234,6 @@ CodeGenTypes::arrangeCXXDestructor(const CXXDestructorDecl *D,
assert(FTP->isVariadic() == 0 && "dtor with formal parameters");
FunctionType::ExtInfo extInfo = FTP->getExtInfo();
adjustCXXMethodInfo(*this, extInfo, false);
return arrangeLLVMFunctionInfo(resultType, argTypes, extInfo,
RequiredArgs::All);
}
@ -406,7 +392,6 @@ CodeGenTypes::arrangeCXXMethodCall(const CallArgList &args,
argTypes.push_back(Context.getCanonicalParamType(i->Ty));
FunctionType::ExtInfo info = FPT->getExtInfo();
adjustCXXMethodInfo(*this, info, FPT->isVariadic());
return arrangeLLVMFunctionInfo(GetReturnType(FPT->getResultType()),
argTypes, info, required);
}

View File

@ -1262,7 +1262,7 @@ public:
// that when AVX types are involved: the ABI explicitly states it is
// undefined, and it doesn't work in practice because of how the ABI
// defines varargs anyway.
if (fnType->getCallConv() == CC_Default || fnType->getCallConv() == CC_C) {
if (fnType->getCallConv() == CC_C) {
bool HasAVXType = false;
for (CallArgList::const_iterator
it = args.begin(), ie = args.end(); it != ie; ++it) {

View File

@ -2201,17 +2201,11 @@ static bool canRedefineFunction(const FunctionDecl *FD,
FD->getStorageClass() == SC_Extern);
}
/// Is the given calling convention the ABI default for the given
/// declaration?
static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) {
CallingConv ABIDefaultCC;
if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) {
ABIDefaultCC = S.Context.getDefaultCXXMethodCallConv(D->isVariadic());
} else {
// Free C function or a static method.
ABIDefaultCC = (S.Context.getLangOpts().MRTD ? CC_X86StdCall : CC_C);
}
return ABIDefaultCC == CC;
const AttributedType *Sema::getCallingConvAttributedType(QualType T) const {
const AttributedType *AT = T->getAs<AttributedType>();
while (AT && !AT->isCallingConv())
AT = AT->getModifiedType()->getAs<AttributedType>();
return AT;
}
template <typename T>
@ -2287,9 +2281,6 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
else
PrevDiag = diag::note_previous_declaration;
QualType OldQType = Context.getCanonicalType(Old->getType());
QualType NewQType = Context.getCanonicalType(New->getType());
// Don't complain about this if we're in GNU89 mode and the old function
// is an extern inline function.
// Don't complain about specializations. They are not supposed to have
@ -2309,53 +2300,52 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S,
}
}
// If a function is first declared with a calling convention, but is
// later declared or defined without one, the second decl assumes the
// calling convention of the first.
// If a function is first declared with a calling convention, but is later
// declared or defined without one, all following decls assume the calling
// convention of the first.
//
// It's OK if a function is first declared without a calling convention,
// but is later declared or defined with the default calling convention.
//
// For the new decl, we have to look at the NON-canonical type to tell the
// difference between a function that really doesn't have a calling
// convention and one that is declared cdecl. That's because in
// canonicalization (see ASTContext.cpp), cdecl is canonicalized away
// because it is the default calling convention.
// To test if either decl has an explicit calling convention, we look for
// AttributedType sugar nodes on the type as written. If they are missing or
// were canonicalized away, we assume the calling convention was implicit.
//
// Note also that we DO NOT return at this point, because we still have
// other tests to run.
QualType OldQType = Context.getCanonicalType(Old->getType());
QualType NewQType = Context.getCanonicalType(New->getType());
const FunctionType *OldType = cast<FunctionType>(OldQType);
const FunctionType *NewType = New->getType()->getAs<FunctionType>();
const FunctionType *NewType = cast<FunctionType>(NewQType);
FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo();
FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo();
bool RequiresAdjustment = false;
if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) {
// Fast path: nothing to do.
// Inherit the CC from the previous declaration if it was specified
// there but not here.
} else if (NewTypeInfo.getCC() == CC_Default) {
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) {
FunctionDecl *First = Old->getFirstDeclaration();
const FunctionType *FT =
First->getType().getCanonicalType()->castAs<FunctionType>();
FunctionType::ExtInfo FI = FT->getExtInfo();
bool NewCCExplicit = getCallingConvAttributedType(New->getType());
if (!NewCCExplicit) {
// Inherit the CC from the previous declaration if it was specified
// there but not here.
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
} else {
// Calling conventions aren't compatible, so complain.
bool FirstCCExplicit = getCallingConvAttributedType(First->getType());
Diag(New->getLocation(), diag::err_cconv_change)
<< FunctionType::getNameForCallConv(NewTypeInfo.getCC())
<< !FirstCCExplicit
<< (!FirstCCExplicit ? "" :
FunctionType::getNameForCallConv(FI.getCC()));
// Don't complain about mismatches when the default CC is
// effectively the same as the explict one. Only Old decl contains correct
// information about storage class of CXXMethod.
} else if (OldTypeInfo.getCC() == CC_Default &&
isABIDefaultCC(*this, NewTypeInfo.getCC(), Old)) {
NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC());
RequiresAdjustment = true;
} else if (!Context.isSameCallConv(OldTypeInfo.getCC(),
NewTypeInfo.getCC())) {
// Calling conventions really aren't compatible, so complain.
Diag(New->getLocation(), diag::err_cconv_change)
<< FunctionType::getNameForCallConv(NewTypeInfo.getCC())
<< (OldTypeInfo.getCC() == CC_Default)
<< (OldTypeInfo.getCC() == CC_Default ? "" :
FunctionType::getNameForCallConv(OldTypeInfo.getCC()));
Diag(Old->getLocation(), diag::note_previous_declaration);
return true;
// Put the note on the first decl, since it is the one that matters.
Diag(First->getLocation(), diag::note_previous_declaration);
return true;
}
}
// FIXME: diagnose the other way around?
@ -6463,6 +6453,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_invalid_thread)
<< DeclSpec::getSpecifierName(TSCS);
if (DC->isRecord() &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
!D.getDeclSpec().isFriendSpecified())
adjustMemberFunctionCC(R);
bool isFriend = false;
FunctionTemplateDecl *FunctionTemplate = 0;
bool isExplicitSpecialization = false;
@ -7144,7 +7139,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Turn this into a variadic function with no parameters.
const FunctionType *FT = NewFD->getType()->getAs<FunctionType>();
FunctionProtoType::ExtProtoInfo EPI;
FunctionProtoType::ExtProtoInfo EPI(
Context.getDefaultCallingConvention(true, false));
EPI.Variadic = true;
EPI.ExtInfo = FT->getExtInfo();

View File

@ -4435,6 +4435,21 @@ updateExceptionSpec(Sema &S, FunctionDecl *FD, const FunctionProtoType *FPT,
FPT->getArgTypes(), EPI));
}
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
CXXMethodDecl *MD) {
FunctionProtoType::ExtProtoInfo EPI;
// Build an exception specification pointing back at this member.
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MD;
// Set the calling convention to the default for C++ instance methods.
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(
S.Context.getDefaultCallingConvention(/*IsVariadic=*/false,
/*IsCXXMethod=*/true));
return EPI;
}
void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) {
const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
if (FPT->getExceptionSpecType() != EST_Unevaluated)
@ -4631,7 +4646,9 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
void Sema::CheckExplicitlyDefaultedMemberExceptionSpec(
CXXMethodDecl *MD, const FunctionProtoType *SpecifiedType) {
// Compute the implicit exception specification.
FunctionProtoType::ExtProtoInfo EPI;
CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false,
/*IsCXXMethod=*/true);
FunctionProtoType::ExtProtoInfo EPI(CC);
computeImplicitExceptionSpec(*this, MD->getLocation(), MD).getEPI(EPI);
const FunctionProtoType *ImplicitType = cast<FunctionProtoType>(
Context.getFunctionType(Context.VoidTy, None, EPI));
@ -7891,9 +7908,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
DefaultCon->setImplicit();
// Build an exception specification pointing back at this constructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = DefaultCon;
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, DefaultCon);
DefaultCon->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
// We don't need to use SpecialMemberIsTrivial here; triviality for default
@ -8355,9 +8370,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
Destructor->setImplicit();
// Build an exception specification pointing back at this destructor.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = Destructor;
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor);
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
AddOverriddenMethods(ClassDecl, Destructor);
@ -8861,9 +8874,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
CopyAssignment->setImplicit();
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyAssignment;
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, CopyAssignment);
CopyAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
@ -9375,9 +9387,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
MoveAssignment->setImplicit();
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveAssignment;
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, MoveAssignment);
MoveAssignment->setType(Context.getFunctionType(RetType, ArgType, EPI));
// Add the parameter to the operator.
@ -9732,9 +9743,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
CopyConstructor->setDefaulted();
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = CopyConstructor;
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, CopyConstructor);
CopyConstructor->setType(
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
@ -9922,9 +9932,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
MoveConstructor->setDefaulted();
// Build an exception specification pointing back at this member.
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExceptionSpecType = EST_Unevaluated;
EPI.ExceptionSpecDecl = MoveConstructor;
FunctionProtoType::ExtProtoInfo EPI =
getImplicitMethodEPI(*this, MoveConstructor);
MoveConstructor->setType(
Context.getFunctionType(Context.VoidTy, ArgType, EPI));
@ -11646,27 +11655,11 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
if (NewCC == OldCC)
return false;
// If either of the calling conventions are set to "default", we need to pick
// something more sensible based on the target. This supports code where the
// one method explicitly sets thiscall, and another has no explicit calling
// convention.
CallingConv Default =
Context.getTargetInfo().getDefaultCallingConv(TargetInfo::CCMT_Member);
if (NewCC == CC_Default)
NewCC = Default;
if (OldCC == CC_Default)
OldCC = Default;
// If the calling conventions still don't match, then report the error
if (NewCC != OldCC) {
Diag(New->getLocation(),
diag::err_conflicting_overriding_cc_attributes)
<< New->getDeclName() << New->getType() << Old->getType();
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
}
return false;
Diag(New->getLocation(),
diag::err_conflicting_overriding_cc_attributes)
<< New->getDeclName() << New->getType() << Old->getType();
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
return true;
}
bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,

View File

@ -539,7 +539,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// C++11 [expr.prim.lambda]p4:
// If a lambda-expression does not include a lambda-declarator, it is as
// if the lambda-declarator were ().
FunctionProtoType::ExtProtoInfo EPI;
FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
EPI.HasTrailingReturn = true;
EPI.TypeQuals |= DeclSpec::TQ_const;
QualType MethodTy = Context.getFunctionType(Context.DependentTy, None,
@ -819,17 +820,20 @@ static void addFunctionPointerConversion(Sema &S,
QualType FunctionTy;
{
FunctionProtoType::ExtProtoInfo ExtInfo = Proto->getExtProtoInfo();
CallingConv CC = S.Context.getDefaultCallingConvention(
Proto->isVariadic(), /*IsCXXMethod=*/false);
ExtInfo.ExtInfo = ExtInfo.ExtInfo.withCallingConv(CC);
ExtInfo.TypeQuals = 0;
FunctionTy = S.Context.getFunctionType(Proto->getResultType(),
Proto->getArgTypes(), ExtInfo);
FunctionPtrTy = S.Context.getPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention(
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
ExtInfo.TypeQuals = Qualifiers::Const;
QualType ConvTy =
S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo);
QualType ConvTy = S.Context.getFunctionType(FunctionPtrTy, None, ExtInfo);
SourceLocation Loc = IntroducerRange.getBegin();
DeclarationName Name
= S.Context.DeclarationNames.getCXXConversionFunctionName(
@ -893,8 +897,9 @@ static void addBlockPointerConversion(Sema &S,
Proto->getResultType(), Proto->getArgTypes(), ExtInfo);
BlockPtrTy = S.Context.getBlockPointerType(FunctionTy);
}
FunctionProtoType::ExtProtoInfo ExtInfo;
FunctionProtoType::ExtProtoInfo ExtInfo(S.Context.getDefaultCallingConvention(
/*IsVariadic=*/false, /*IsCXXMethod=*/true));
ExtInfo.TypeQuals = Qualifiers::Const;
QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ExtInfo);

View File

@ -728,7 +728,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) {
// function to have, if it were to match the name given.
// FIXME: Calling convention!
FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo();
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default);
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C);
EPI.ExceptionSpecType = EST_None;
EPI.NumExceptions = 0;
QualType ExpectedType

View File

@ -1784,6 +1784,8 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class,
}
}
// FIXME: Adjust member function pointer calling conventions.
return Context.getMemberPointerType(T, Class.getTypePtr());
}
@ -2420,6 +2422,53 @@ static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,
}
}
/// Helper for figuring out the default CC for a function declarator type. If
/// this is the outermost chunk, then we can determine the CC from the
/// declarator context. If not, then this could be either a member function
/// type or normal function type.
static CallingConv
getCCForDeclaratorChunk(Sema &S, Declarator &D,
const DeclaratorChunk::FunctionTypeInfo &FTI,
unsigned ChunkIndex) {
assert(D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function);
bool IsCXXInstanceMethod = false;
if (S.getLangOpts().CPlusPlus) {
// Look inwards through parentheses to see if this chunk will form a
// member pointer type or if we're the declarator. Any type attributes
// between here and there will override the CC we choose here.
unsigned I = ChunkIndex;
bool FoundNonParen = false;
while (I && !FoundNonParen) {
--I;
if (D.getTypeObject(I).Kind != DeclaratorChunk::Paren)
FoundNonParen = true;
}
if (FoundNonParen) {
// If we're not the declarator, we're a regular function type unless we're
// in a member pointer.
IsCXXInstanceMethod =
D.getTypeObject(I).Kind == DeclaratorChunk::MemberPointer;
} else {
// We're the innermost decl chunk, so must be a function declarator.
assert(D.isFunctionDeclarator());
// If we're inside a record, we're declaring a method, but it could be
// static.
IsCXXInstanceMethod =
(D.getContext() == Declarator::MemberContext &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
!D.getDeclSpec().isFriendSpecified());
}
}
return S.Context.getDefaultCallingConvention(FTI.isVariadic,
IsCXXInstanceMethod);
}
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@ -2793,9 +2842,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (FTI.isAmbiguous)
warnAboutAmbiguousFunction(S, D, DeclType, T);
FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex));
if (!FTI.NumArgs && !FTI.isVariadic && !LangOpts.CPlusPlus) {
// Simple void foo(), where the incoming T is the result type.
T = Context.getFunctionNoProtoType(T);
T = Context.getFunctionNoProtoType(T, EI);
} else {
// We allow a zero-parameter variadic function in C if the
// function is marked with the "overloadable" attribute. Scan
@ -2820,11 +2871,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
S.Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
D.setInvalidType(true);
// Recover by creating a K&R-style function type.
T = Context.getFunctionNoProtoType(T);
T = Context.getFunctionNoProtoType(T, EI);
break;
}
FunctionProtoType::ExtProtoInfo EPI;
EPI.ExtInfo = EI;
EPI.Variadic = FTI.isVariadic;
EPI.HasTrailingReturn = FTI.hasTrailingReturnType();
EPI.TypeQuals = FTI.TypeQuals;
@ -4414,20 +4466,19 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
const FunctionType *fn = unwrapped.get();
CallingConv CCOld = fn->getCallConv();
if (S.Context.getCanonicalCallConv(CC) ==
S.Context.getCanonicalCallConv(CCOld)) {
FunctionType::ExtInfo EI= unwrapped.get()->getExtInfo().withCallingConv(CC);
type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
return true;
}
AttributedType::Kind CCAttrKind = getCCTypeAttrKind(attr);
if (CCOld != (S.LangOpts.MRTD ? CC_X86StdCall : 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);
attr.setInvalid();
return true;
if (CC != CCOld) {
// Error out on when there's already an attribute on the type
// and the CCs don't match.
const AttributedType *AT = S.getCallingConvAttributedType(type);
if (AT && AT->getAttrKind() != CCAttrKind) {
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< FunctionType::getNameForCallConv(CC)
<< FunctionType::getNameForCallConv(CCOld);
attr.setInvalid();
return true;
}
}
// Diagnose the use of X86 fastcall on varargs or unprototyped functions.
@ -4463,10 +4514,38 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC);
QualType Equivalent =
unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
type = S.Context.getAttributedType(getCCTypeAttrKind(attr), type, Equivalent);
type = S.Context.getAttributedType(CCAttrKind, type, Equivalent);
return true;
}
void Sema::adjustMemberFunctionCC(QualType &T) {
const FunctionType *FT = T->castAs<FunctionType>();
bool IsVariadic = (isa<FunctionProtoType>(FT) &&
cast<FunctionProtoType>(FT)->isVariadic());
CallingConv CC = FT->getCallConv();
CallingConv DefaultCC =
Context.getDefaultCallingConvention(IsVariadic, /*IsCXXMethod=*/false);
if (CC != DefaultCC)
return;
// Check if there was an explicit attribute, but only look through parens.
// The intent is to look for an attribute on the current declarator, but not
// one that came from a typedef.
QualType R = T.IgnoreParens();
while (const AttributedType *AT = dyn_cast<AttributedType>(R)) {
if (AT->isCallingConv())
return;
R = AT->getModifiedType().IgnoreParens();
}
// FIXME: This loses sugar. This should probably be fixed with an implicit
// AttributedType node that adjusts the convention.
CC = Context.getDefaultCallingConvention(IsVariadic, /*IsCXXMethod=*/true);
FT = Context.adjustFunctionType(FT, FT->getExtInfo().withCallingConv(CC));
FunctionTypeUnwrapper Unwrapped(*this, T);
T = Unwrapped.wrap(*this, FT);
}
/// Handle OpenCL image access qualifiers: read_only, write_only, read_write
static void HandleOpenCLImageAccessAttribute(QualType& CurType,
const AttributeList &Attr,

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -mrtd -triple i386-unknown-freebsd9.0 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -mrtd -triple i386-unknown-unknown -std=c89 -emit-llvm -o - %s | FileCheck %s
void baz(int arg);
@ -14,4 +14,13 @@ void foo(int arg) {
// CHECK: declare x86_stdcallcc void @baz(i32)
void qux(int arg, ...) { }
// CHECK: define void @qux(i32 %arg, ...)
void quux(int a1, int a2, int a3) {
qux(a1, a2, a3);
}
// CHECK-LABEL: define x86_stdcallcc void @quux
// CHECK: call void (i32, ...)* @qux
// CHECK: attributes [[NUW]] = { nounwind{{.*}} }

View File

@ -56,3 +56,7 @@ PROC __attribute__((cdecl)) ctest4(const char *x) {}
void __attribute__((pnaclcall)) pnaclfunc(float *a) {} // expected-warning {{calling convention 'pnaclcall' ignored for this target}}
void __attribute__((intel_ocl_bicc)) inteloclbifunc(float *a) {}
typedef void typedef_fun_t(int);
typedef_fun_t typedef_fun; // expected-note {{previous declaration is here}}
void __attribute__((stdcall)) typedef_fun(int x) { } // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}

40
clang/test/Sema/mrtd.c Normal file
View File

@ -0,0 +1,40 @@
// RUN: %clang_cc1 -DMRTD -mrtd -triple i386-unknown-unknown -verify %s
// RUN: %clang_cc1 -triple i386-unknown-unknown -verify %s
#ifndef MRTD
// expected-note@+5 {{previous declaration is here}}
// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}}
// expected-note@+5 {{previous declaration is here}}
// expected-error@+5 {{function declared 'stdcall' here was previously declared without calling convention}}
#endif
void nonvariadic1(int a, int b, int c);
void __attribute__((stdcall)) nonvariadic1(int a, int b, int c);
void nonvariadic2(int a, int b, int c);
void __attribute__((stdcall)) nonvariadic2(int a, int b, int c) { }
// expected-note@+2 {{previous declaration is here}}
// expected-error@+2 {{function declared 'stdcall' here was previously declared without calling convention}}
void variadic(int a, ...);
void __attribute__((stdcall)) variadic(int a, ...);
#ifdef MRTD
// expected-note@+3 {{previous definition is here}}
// expected-error@+3 {{redefinition of 'a' with a different type: 'void ((*))(int, int) __attribute__((cdecl))' vs 'void (*)(int, int) __attribute__((stdcall))'}}
#endif
extern void (*a)(int, int);
__attribute__((cdecl)) extern void (*a)(int, int);
extern void (*b)(int, ...);
__attribute__((cdecl)) extern void (*b)(int, ...);
#ifndef MRTD
// expected-note@+3 {{previous definition is here}}
// expected-error@+3 {{redefinition of 'c' with a different type: 'void ((*))(int, int) __attribute__((stdcall))' vs 'void (*)(int, int)'}}
#endif
extern void (*c)(int, int);
__attribute__((stdcall)) extern void (*c)(int, int);
// expected-note@+2 {{previous definition is here}}
// expected-error@+2 {{redefinition of 'd' with a different type: 'void ((*))(int, ...) __attribute__((stdcall))' vs 'void (*)(int, ...)'}}
extern void (*d)(int, ...);
__attribute__((stdcall)) extern void (*d)(int, ...);

View File

@ -0,0 +1,387 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -fms-extensions -cxx-abi microsoft -verify -triple i686-pc-win32 %s
// Pointers to free functions
void free_func_default();
void __cdecl free_func_cdecl();
void __stdcall free_func_stdcall();
void __fastcall free_func_fastcall();
typedef void ( *fptr_default)();
typedef void (__cdecl *fptr_cdecl)();
typedef void (__stdcall *fptr_stdcall)();
typedef void (__fastcall *fptr_fastcall)();
// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_default' (aka 'void (*)()') for 1st argument}}
void cb_fptr_default(fptr_default ptr);
// expected-note@+4 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
// expected-note@+3 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((stdcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (*)() __attribute__((fastcall))' to 'fptr_cdecl' (aka 'void (*)()') for 1st argument}}
void cb_fptr_cdecl(fptr_cdecl ptr);
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fptr_stdcall' (aka 'void (*)() __attribute__((stdcall))') for 1st argument}}
void cb_fptr_stdcall(fptr_stdcall ptr);
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fptr_fastcall' (aka 'void (*)() __attribute__((fastcall))') for 1st argument}}
void cb_fptr_fastcall(fptr_fastcall ptr);
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'const fptr_default' (aka 'void (*const)()') for 1st argument}}
void cb_fptr_const_default(const fptr_default ptr);
void call_free_func() {
cb_fptr_default(free_func_default);
cb_fptr_default(free_func_cdecl);
cb_fptr_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
cb_fptr_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
cb_fptr_default(&free_func_default);
cb_fptr_default(&free_func_cdecl);
cb_fptr_default(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
cb_fptr_default(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_default'}}
cb_fptr_cdecl(free_func_default);
cb_fptr_cdecl(free_func_cdecl);
cb_fptr_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
cb_fptr_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
cb_fptr_cdecl(&free_func_default);
cb_fptr_cdecl(&free_func_cdecl);
cb_fptr_cdecl(&free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
cb_fptr_cdecl(&free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_cdecl'}}
cb_fptr_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
cb_fptr_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
cb_fptr_stdcall(free_func_stdcall);
cb_fptr_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_stdcall'}}
cb_fptr_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
cb_fptr_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
cb_fptr_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_fastcall'}}
cb_fptr_fastcall(free_func_fastcall);
cb_fptr_const_default(free_func_default);
cb_fptr_const_default(free_func_cdecl);
cb_fptr_const_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}}
cb_fptr_const_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fptr_const_default'}}
}
// Pointers to variadic functions
// variadic function can't declared stdcall or fastcall
void free_func_variadic_default(int, ...);
void __cdecl free_func_variadic_cdecl(int, ...);
typedef void ( *fptr_variadic_default)(int, ...);
typedef void (__cdecl *fptr_variadic_cdecl)(int, ...);
void cb_fptr_variadic_default(fptr_variadic_default ptr);
void cb_fptr_variadic_cdecl(fptr_variadic_cdecl ptr);
void call_free_variadic_func() {
cb_fptr_variadic_default(free_func_variadic_default);
cb_fptr_variadic_default(free_func_variadic_cdecl);
cb_fptr_variadic_default(&free_func_variadic_default);
cb_fptr_variadic_default(&free_func_variadic_cdecl);
cb_fptr_variadic_cdecl(free_func_variadic_default);
cb_fptr_variadic_cdecl(free_func_variadic_cdecl);
cb_fptr_variadic_cdecl(&free_func_variadic_default);
cb_fptr_variadic_cdecl(&free_func_variadic_cdecl);
}
// References to functions
typedef void ( &fref_default)();
typedef void (__cdecl &fref_cdecl)();
typedef void (__stdcall &fref_stdcall)();
typedef void (__fastcall &fref_fastcall)();
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_default' (aka 'void (&)()') for 1st argument}}
void cb_fref_default(fref_default ptr);
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_cdecl' (aka 'void (&)()') for 1st argument}}
void cb_fref_cdecl(fref_cdecl ptr);
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((fastcall))' to 'fref_stdcall' (aka 'void (&)() __attribute__((stdcall))') for 1st argument}}
void cb_fref_stdcall(fref_stdcall ptr);
// expected-note@+3 {{candidate function not viable: no known conversion from 'void ()' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void () __attribute__((cdecl))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void () __attribute__((stdcall))' to 'fref_fastcall' (aka 'void (&)() __attribute__((fastcall))') for 1st argument}}
void cb_fref_fastcall(fref_fastcall ptr);
void call_free_func_ref() {
cb_fref_default(free_func_default);
cb_fref_default(free_func_cdecl);
cb_fref_default(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_default'}}
cb_fref_default(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_default'}}
cb_fref_cdecl(free_func_default);
cb_fref_cdecl(free_func_cdecl);
cb_fref_cdecl(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}}
cb_fref_cdecl(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_cdecl'}}
cb_fref_stdcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
cb_fref_stdcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
cb_fref_stdcall(free_func_stdcall);
cb_fref_stdcall(free_func_fastcall); // expected-error {{no matching function for call to 'cb_fref_stdcall'}}
cb_fref_fastcall(free_func_default); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
cb_fref_fastcall(free_func_cdecl); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
cb_fref_fastcall(free_func_stdcall); // expected-error {{no matching function for call to 'cb_fref_fastcall'}}
cb_fref_fastcall(free_func_fastcall);
}
// References to variadic functions
// variadic function can't declared stdcall or fastcall
typedef void ( &fref_variadic_default)(int, ...);
typedef void (__cdecl &fref_variadic_cdecl)(int, ...);
void cb_fref_variadic_default(fptr_variadic_default ptr);
void cb_fref_variadic_cdecl(fptr_variadic_cdecl ptr);
void call_free_variadic_func_ref() {
cb_fref_variadic_default(free_func_variadic_default);
cb_fref_variadic_default(free_func_variadic_cdecl);
cb_fref_variadic_cdecl(free_func_variadic_default);
cb_fref_variadic_cdecl(free_func_variadic_cdecl);
}
// Pointers to members
namespace NonVariadic {
struct A {
void member_default();
void __cdecl member_cdecl();
void __thiscall member_thiscall();
};
struct B : public A {
};
struct C {
void member_default();
void __cdecl member_cdecl();
void __thiscall member_thiscall();
};
typedef void ( A::*memb_a_default)();
typedef void (__cdecl A::*memb_a_cdecl)();
typedef void (__thiscall A::*memb_a_thiscall)();
typedef void ( B::*memb_b_default)();
typedef void (__cdecl B::*memb_b_cdecl)();
typedef void (__thiscall B::*memb_b_thiscall)();
typedef void ( C::*memb_c_default)();
typedef void (__cdecl C::*memb_c_cdecl)();
typedef void (__thiscall C::*memb_c_thiscall)();
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_default' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_a_default(memb_a_default ptr);
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_a_cdecl' (aka 'void (NonVariadic::A::*)() __attribute__((cdecl))') for 1st argument}}
void cb_memb_a_cdecl(memb_a_cdecl ptr);
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_a_thiscall' (aka 'void (NonVariadic::A::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_a_thiscall(memb_a_thiscall ptr);
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_default' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_b_default(memb_b_default ptr);
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_b_cdecl' (aka 'void (NonVariadic::B::*)() __attribute__((cdecl))') for 1st argument}}
void cb_memb_b_cdecl(memb_b_cdecl ptr);
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_b_thiscall' (aka 'void (NonVariadic::B::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_b_thiscall(memb_b_thiscall ptr);
// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_default' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_c_default(memb_c_default ptr);
// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_cdecl' (aka 'void (NonVariadic::C::*)() __attribute__((cdecl))') for 1st argument}}
void cb_memb_c_cdecl(memb_c_cdecl ptr);
// expected-note@+3 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((cdecl))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (NonVariadic::A::*)() __attribute__((thiscall))' to 'memb_c_thiscall' (aka 'void (NonVariadic::C::*)() __attribute__((thiscall))') for 1st argument}}
void cb_memb_c_thiscall(memb_c_thiscall ptr);
void call_member() {
cb_memb_a_default(&A::member_default);
cb_memb_a_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_default'}}
cb_memb_a_default(&A::member_thiscall);
cb_memb_a_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}}
cb_memb_a_cdecl(&A::member_cdecl);
cb_memb_a_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_a_cdecl'}}
cb_memb_a_thiscall(&A::member_default);
cb_memb_a_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_a_thiscall'}}
cb_memb_a_thiscall(&A::member_thiscall);
}
void call_member_inheritance() {
cb_memb_b_default(&A::member_default);
cb_memb_b_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_default'}}
cb_memb_b_default(&A::member_thiscall);
cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
cb_memb_c_default(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
cb_memb_b_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}}
cb_memb_b_cdecl(&A::member_cdecl);
cb_memb_b_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_b_cdecl'}}
cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
cb_memb_c_cdecl(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
cb_memb_b_thiscall(&A::member_default);
cb_memb_b_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_b_thiscall'}}
cb_memb_b_thiscall(&A::member_thiscall);
cb_memb_c_thiscall(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
cb_memb_c_thiscall(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
cb_memb_c_thiscall(&A::member_thiscall); // expected-error {{no matching function for call to 'cb_memb_c_thiscall'}}
}
} // end namespace NonVariadic
namespace Variadic {
struct A {
void member_default(int, ...);
void __cdecl member_cdecl(int, ...);
void __thiscall member_thiscall(int, ...);
};
struct B : public A {
};
struct C {
void member_default(int, ...);
void __cdecl member_cdecl(int, ...);
};
typedef void ( A::*memb_a_default)(int, ...);
typedef void (__cdecl A::*memb_a_cdecl)(int, ...);
typedef void ( B::*memb_b_default)(int, ...);
typedef void (__cdecl B::*memb_b_cdecl)(int, ...);
typedef void ( C::*memb_c_default)(int, ...);
typedef void (__cdecl C::*memb_c_cdecl)(int, ...);
void cb_memb_a_default(memb_a_default ptr);
void cb_memb_a_cdecl(memb_a_cdecl ptr);
void cb_memb_b_default(memb_b_default ptr);
void cb_memb_b_cdecl(memb_b_cdecl ptr);
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_default' (aka 'void (Variadic::C::*)(int, ...)') for 1st argument}}
void cb_memb_c_default(memb_c_default ptr);
// expected-note@+2 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...)' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
// expected-note@+1 {{candidate function not viable: no known conversion from 'void (Variadic::A::*)(int, ...) __attribute__((cdecl))' to 'memb_c_cdecl' (aka 'void (Variadic::C::*)(int, ...) __attribute__((cdecl))') for 1st argument}}
void cb_memb_c_cdecl(memb_c_cdecl ptr);
void call_member() {
cb_memb_a_default(&A::member_default);
cb_memb_a_default(&A::member_cdecl);
cb_memb_a_cdecl(&A::member_default);
cb_memb_a_cdecl(&A::member_cdecl);
}
void call_member_inheritance() {
cb_memb_b_default(&A::member_default);
cb_memb_b_default(&A::member_cdecl);
cb_memb_c_default(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
cb_memb_c_default(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_default'}}
cb_memb_b_cdecl(&A::member_default);
cb_memb_b_cdecl(&A::member_cdecl);
cb_memb_c_cdecl(&A::member_default); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
cb_memb_c_cdecl(&A::member_cdecl); // expected-error {{no matching function for call to 'cb_memb_c_cdecl'}}
}
} // end namespace Variadic
namespace MultiChunkDecls {
// Try to test declarators that have multiple DeclaratorChunks.
struct A {
void __thiscall member_thiscall(int);
};
void (A::*return_mptr(short))(int) {
return &A::member_thiscall;
}
void (A::*(*return_fptr_mptr(char))(short))(int) {
return return_mptr;
}
typedef void (A::*mptr_t)(int);
mptr_t __stdcall return_mptr_std(short) {
return &A::member_thiscall;
}
void (A::*(*return_fptr_std_mptr(char))(short))(int) {
return return_mptr_std; // expected-error {{cannot initialize return object of type 'void (MultiChunkDecls::A::*(*)(short))(int) __attribute__((thiscall))' with an lvalue of type 'mptr_t (short) __attribute__((stdcall))'}}
}
void call_return() {
A o;
void (A::*(*fptr)(short))(int) = return_fptr_mptr('a');
void (A::*mptr)(int) = fptr(1);
(o.*mptr)(2);
}
} // end namespace MultiChunkDecls
namespace MemberPointers {
struct A {
void __thiscall method_thiscall();
void __cdecl method_cdecl();
void __stdcall method_stdcall();
void __fastcall method_fastcall();
};
void ( A::*mp1)() = &A::method_thiscall;
void (__cdecl A::*mp2)() = &A::method_cdecl;
void (__stdcall A::*mp3)() = &A::method_stdcall;
void (__fastcall A::*mp4)() = &A::method_fastcall;
// Use a typedef to form the member pointer and verify that cdecl is adjusted.
typedef void ( fun_default)();
typedef void (__cdecl fun_cdecl)();
typedef void (__stdcall fun_stdcall)();
typedef void (__fastcall fun_fastcall)();
// FIXME: Adjust cdecl to thiscall when forming a member pointer.
//fun_default A::*td1 = &A::method_thiscall;
fun_cdecl A::*td2 = &A::method_cdecl;
fun_stdcall A::*td3 = &A::method_stdcall;
fun_fastcall A::*td4 = &A::method_fastcall;
// Round trip the function type through a template, and verify that only cdecl
// gets adjusted.
template<typename Fn> struct X {
typedef Fn A::*p;
};
// FIXME: Adjust cdecl to thiscall when forming a member pointer.
//X<void ()>::p tmpl1 = &A::method_thiscall;
//X<void __cdecl ()>::p tmpl2 = &A::method_thiscall;
X<void __stdcall ()>::p tmpl3 = &A::method_stdcall;
X<void __fastcall ()>::p tmpl4 = &A::method_fastcall;
} // end namespace MemberPointers
// Test that lambdas that capture nothing convert to cdecl function pointers.
namespace Lambdas {
void pass_fptr_cdecl (void (__cdecl *fp)());
void pass_fptr_stdcall (void (__stdcall *fp)()); // expected-note {{candidate function not viable}}
void pass_fptr_fastcall(void (__fastcall *fp)()); // expected-note {{candidate function not viable}}
void conversion_to_fptr() {
pass_fptr_cdecl ([]() { } );
pass_fptr_stdcall ([]() { } ); // expected-error {{no matching function for call}}
pass_fptr_fastcall([]() { } ); // expected-error {{no matching function for call}}
}
}

View File

@ -1,21 +1,24 @@
// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -fms-extensions -verify %s
typedef void void_fun_t();
typedef void __cdecl cdecl_fun_t();
// Pointers to free functions
void free_func_default();
void __cdecl free_func_cdecl();
void __stdcall free_func_stdcall(); // expected-note {{previous declaration is here}}
void free_func_default(); // expected-note 2 {{previous declaration is here}}
void __cdecl free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
void __stdcall free_func_stdcall(); // expected-note 2 {{previous declaration is here}}
void __fastcall free_func_fastcall(); // expected-note 2 {{previous declaration is here}}
void __cdecl free_func_default(); // expected-note 2 {{previous declaration is here}}
void __cdecl free_func_default();
void __stdcall free_func_default(); // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void __fastcall free_func_default(); // expected-error {{function declared 'fastcall' here was previously declared without calling convention}}
void free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
void free_func_cdecl();
void __stdcall free_func_cdecl(); // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
void __fastcall free_func_cdecl(); // expected-error {{function declared 'fastcall' here was previously declared 'cdecl'}}
void free_func_stdcall();
void __cdecl free_func_stdcall(); // expected-error {{function declared 'cdecl' here was previously declared 'stdcall'}}
void free_func_stdcall(); // expected-note {{previous declaration is here}}
void __fastcall free_func_stdcall(); // expected-error {{function declared 'fastcall' here was previously declared 'stdcall'}}
void __cdecl free_func_fastcall(); // expected-error {{function declared 'cdecl' here was previously declared 'fastcall'}}
@ -41,15 +44,16 @@ struct S {
void __thiscall member_thiscall1();
void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}}
// Unless attributed, typedefs carry no calling convention and use the default
// based on context.
void_fun_t member_typedef_default; // expected-note {{previous declaration is here}}
cdecl_fun_t member_typedef_cdecl; // expected-note {{previous declaration is here}}
__stdcall void_fun_t member_typedef_stdcall;
// Typedefs carrying the __cdecl convention are adjusted to __thiscall.
void_fun_t member_typedef_default; // expected-note {{previous declaration is here}}
cdecl_fun_t member_typedef_cdecl1; // expected-note {{previous declaration is here}}
cdecl_fun_t __cdecl member_typedef_cdecl2;
void_fun_t __stdcall member_typedef_stdcall;
// Static member functions can't be __thiscall
static void static_member_default1();
static void static_member_default2(); // expected-note {{previous declaration is here}}
static void static_member_default2();
static void static_member_default3(); // expected-note {{previous declaration is here}}
static void __cdecl static_member_cdecl1();
static void __cdecl static_member_cdecl2(); // expected-note {{previous declaration is here}}
static void __stdcall static_member_stdcall1();
@ -66,8 +70,9 @@ struct S {
void __cdecl S::member_default1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __thiscall S::member_default2() {}
void __cdecl S::member_typedef_default() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __thiscall S::member_typedef_cdecl() {} // expected-error {{function declared 'thiscall' here was previously declared 'cdecl'}}
void __cdecl S::member_typedef_default() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __cdecl S::member_typedef_cdecl1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __cdecl S::member_typedef_cdecl2() {}
void __stdcall S::member_typedef_stdcall() {}
void S::member_cdecl1() {}
@ -76,25 +81,18 @@ void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thi
void S::member_thiscall1() {}
void __cdecl S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}
void __cdecl S::static_member_default1() {}
void __stdcall S::static_member_default2() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void S::static_member_default1() {}
void __cdecl S::static_member_default2() {}
void __stdcall S::static_member_default3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void S::static_member_cdecl1() {}
void __stdcall S::static_member_cdecl2() {} // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
void __cdecl S::member_variadic_default(int x, ...) {
(void)x;
}
void S::member_variadic_cdecl(int x, ...) {
(void)x;
}
void __cdecl S::member_variadic_default(int x, ...) { (void)x; }
void S::member_variadic_cdecl(int x, ...) { (void)x; }
void __cdecl S::static_member_variadic_default(int x, ...) {
(void)x;
}
void S::static_member_variadic_cdecl(int x, ...) {
(void)x;
}
void __cdecl S::static_member_variadic_default(int x, ...) { (void)x; }
void S::static_member_variadic_cdecl(int x, ...) { (void)x; }
// Declare a template using a calling convention.
template <class CharT> inline int __cdecl mystrlen(const CharT *str) {
@ -110,3 +108,39 @@ void use_tmpl(const char *str, const int *ints) {
mystrlen(str);
mystrlen(ints);
}
struct MixedCCStaticOverload {
static void overloaded(int a);
static void __stdcall overloaded(short a);
};
void MixedCCStaticOverload::overloaded(int a) {}
void MixedCCStaticOverload::overloaded(short a) {}
// Friend function decls are cdecl by default, not thiscall. Friend method
// decls should always be redeclarations, because the class cannot be
// incomplete.
struct FriendClass {
void friend_method() {}
};
void __stdcall friend_stdcall1() {}
class MakeFriendDecls {
int x;
friend void FriendClass::friend_method();
friend void friend_default();
friend void friend_stdcall1();
friend void __stdcall friend_stdcall2();
friend void friend_stdcall3(); // expected-note {{previous declaration is here}}
};
void friend_default() {}
void __stdcall friend_stdcall3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void __stdcall friend_stdcall2() {}
// Test functions with multiple attributes.
void __attribute__((noreturn)) __stdcall __attribute__((regparm(1))) multi_attribute(int x);
void multi_attribute(int x) { __builtin_unreachable(); }
// expected-error@+2 {{stdcall and cdecl attributes are not compatible}}
// expected-error@+1 {{fastcall and cdecl attributes are not compatible}}
void __cdecl __cdecl __stdcall __cdecl __fastcall multi_cc(int x);

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple=i686-pc-unknown -fsyntax-only -verify %s -std=c++11
// RUN: %clang_cc1 -triple=i686-pc-unknown -fsyntax-only -verify %s -std=c++11 -cxx-abi microsoft
namespace PR14339 {
class A {
@ -28,6 +28,6 @@ namespace PR14339 {
class F : public E {
public:
void g(); // expected-error{{virtual function 'g' has different calling convention attributes ('void ()') than the function it overrides (which has calling convention 'void () __attribute__((stdcall))'}}
void g(); // expected-error{{virtual function 'g' has different calling convention attributes ('void () __attribute__((thiscall))') than the function it overrides (which has calling convention 'void () __attribute__((stdcall))'}}
};
}

View File

@ -504,7 +504,6 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
if (const FunctionType *FD = T->getAs<FunctionType>()) {
#define TCALLINGCONV(X) case CC_##X: return CXCallingConv_##X
switch (FD->getCallConv()) {
TCALLINGCONV(Default);
TCALLINGCONV(C);
TCALLINGCONV(X86StdCall);
TCALLINGCONV(X86FastCall);