]> granicus.if.org Git - clang/commitdiff
Delete CC_Default and use the target default CC everywhere
authorReid Kleckner <reid@kleckner.net>
Tue, 27 Aug 2013 23:08:25 +0000 (23:08 +0000)
committerReid Kleckner <reid@kleckner.net>
Tue, 27 Aug 2013 23:08:25 +0000 (23:08 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189412 91177308-0d34-0410-b5e6-96231b3b80d8

26 files changed:
include/clang/AST/ASTContext.h
include/clang/AST/Type.h
include/clang/Basic/Specifiers.h
include/clang/Basic/TargetInfo.h
include/clang/Sema/Sema.h
lib/AST/ASTContext.cpp
lib/AST/DumpXML.cpp
lib/AST/ExprCXX.cpp
lib/AST/MicrosoftMangle.cpp
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CGCall.cpp
lib/CodeGen/TargetInfo.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaLookup.cpp
lib/Sema/SemaType.cpp
test/CodeGen/mrtd.c
test/Sema/callingconv.c
test/Sema/mrtd.c [new file with mode: 0644]
test/SemaCXX/calling-conv-compat.cpp [new file with mode: 0644]
test/SemaCXX/decl-microsoft-call-conv.cpp
test/SemaCXX/virtual-override-x86.cpp
tools/libclang/CXType.cpp

index 0e0a62be972041f8afc6dfa0af09c6b325828848..06264efa06825ca645f214b0ff5ad888129707bd 100644 (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.
index 6e2246ba370397d475a4f5f2418c8a4ab4ab9a0b..436fceeb80c226b22647360d30a098f382925add 100644 (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;
index 7fe242ece874947c88820cb1c1d5636fd5c8d75f..d9d5799e04094b647dd208fefb42b8fba553bbf2 100644 (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))
index ec7cdec7ad4399e673bed5ecf6f39ba27d0802e2..1073711ce4a49aac93237200b34ae8448c1c78f3 100644 (file)
@@ -779,7 +779,6 @@ public:
       default:
         return CCCR_Warning;
       case CC_C:
-      case CC_Default:
         return CCCR_OK;
     }
   }
index 749c64d9588058a6a4fb93d008e0e498b5db1086..6722e535f083656e940c1bf0009b2c84d596c1c8 100644 (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);
index 29ddb37525dca5b6de1ca54d51e99dfd75a8fb10..94d9e918e75d3d5d097f05273e87fbefb8862766 100644 (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 {
index be22ae450b62abf0fa9b2b4873844260a45a2a06..9516a4be99a5911b2c36b4a433b4357bb82a9367 100644 (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");
index b76bc2f28497f1e632dce19200a159a3283a4e99..36aa2892f2af7e009e4043d613f3a86683b05576 100644 (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() &&
index 87527c9294aa8aa21e6f7c48fe3642273a571b1d..97edce105cd430d9729ecd646dacce6a66cf0f0c 100644 (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;
index ef423eba879e5440aaac7ab611affb9d378a8027..1bd2d3b98da96110d1f6602bc7f408223f7f5631 100644 (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";
index f6fd886e8a46793380272ff5dfb0b29e07a2d7da..2a4cf52027d422a516d0cabede92e713e03ce507 100644 (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())
index 84f8a347bda9f15cdf05e400467a9c7dcbdeaebd..f4c4226482d5bff0ddcb00e979cdfc2cf2ec7895 100644 (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 {
index 971a2ade1262cd1091ea4b897a2c8d50e4531ea5..ed02c74cdfca25fb0b0d75c44bcb613203349e72 100644 (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);
 }
index 70fc8fed5d47eaffc3abb9092c54f9ea37504d29..b56684ba5c8ade611a15f34f092b10e96207661c 100644 (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) {
index d831c706190ce87e8c654347025d8ed60257323e..748814d934489cbe88a87d25ee92b189c28f262e 100644 (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;
-
-  // 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;
+  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()));
+
+      // 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();
 
index f12f92321ae6b78371e09bd5baeb977af083ce37..bfb96c7ff5e754b892a21ff36b27c4afc255c888 100644 (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,
index ae3a938333f828bf6de595bb4d5843ff78d2585c..242105f789cff8da178dc1eb99b53151c30500b5 100644 (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);
   
index a17a903a5f4e28910446bbd93507c35472c1845a..c00ae69cbe87d043b21492405c2d7efed43abfc6 100644 (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
index 9664937954b98202cbf0ceec991c93098ce77a1c..52b099e197d70f4ad02827825c727dd659914dcf 100644 (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,
index a40a59ac0fcc09abbfa3e12035ab5461a42f56f7..8fa7cf02cead92d583b43f667653d5c08fed76d5 100644 (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{{.*}} }
index ea91675c1983e0acf765da1b150bdb6cf33a71d6..b9adf791b59433518a981d0d05629f1ddbd5db3f 100644 (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}}
diff --git a/test/Sema/mrtd.c b/test/Sema/mrtd.c
new file mode 100644 (file)
index 0000000..653413b
--- /dev/null
@@ -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, ...);
diff --git a/test/SemaCXX/calling-conv-compat.cpp b/test/SemaCXX/calling-conv-compat.cpp
new file mode 100644 (file)
index 0000000..b6cc429
--- /dev/null
@@ -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}}
+}
+
+}
index 9e85e62cf88ecc02391af6a9149186b0064d2c38..7fcf515d679768c9162795fcbfd673b73962b703 100644 (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 {{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);
index ad70d3f22437d68962c3f00277a2ea1e85a5c92f..75d8af3b3ea34c14cb2958880b7f205714bc37bb 100644 (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))'}}
   };
 }
index 3ed388f4a708a568b0babd8b1673d87ee98ac313..6c937c6e52d80ab7baac1f7d5985731c15d4feb2 100644 (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);