]> granicus.if.org Git - clang/commitdiff
Fix declaring class template methods with an attributed typedef
authorReid Kleckner <reid@kleckner.net>
Wed, 31 Jul 2013 21:00:18 +0000 (21:00 +0000)
committerReid Kleckner <reid@kleckner.net>
Wed, 31 Jul 2013 21:00:18 +0000 (21:00 +0000)
This change unifies the logic for template instantiation of methods and
functions declared with typedefs.

It ensures that SubstFunctionType() always fills the Params out param
with non-null ParmVarDecls or returns null.

Reviewers: rsmith

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

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

lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/decl-microsoft-call-conv.cpp
test/SemaTemplate/instantiate-function-params.cpp

index 67b53b4c0a7046242bfd0784e6c412838bbc2735..57eb64d127ae4f96b6a2d850a6761913107407eb 100644 (file)
@@ -1577,6 +1577,9 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
   for (unsigned I = 0, E = FP.getNumArgs(); I != E; ++I) {
     ParmVarDecl *P = FP.getArg(I);
 
+    // This must be synthesized from a typedef.
+    if (!P) continue;
+
     // The parameter's type as written might be dependent even if the
     // decayed type was not dependent.
     if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo())
index ffd7645f71388fc375726418060bb95c79f28215..52075229971a0c8474d2032f3a2bf463d1a08699 100644 (file)
@@ -1233,26 +1233,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
   Function->setLexicalDeclContext(LexicalDC);
 
   // Attach the parameters
-  if (isa<FunctionProtoType>(Function->getType().IgnoreParens())) {
-    // Adopt the already-instantiated parameters into our own context.
-    for (unsigned P = 0; P < Params.size(); ++P)
-      if (Params[P])
-        Params[P]->setOwningFunction(Function);
-  } else {
-    // Since we were instantiated via a typedef of a function type, create
-    // new parameters.
-    const FunctionProtoType *Proto
-      = Function->getType()->getAs<FunctionProtoType>();
-    assert(Proto && "No function prototype in template instantiation?");
-    for (FunctionProtoType::arg_type_iterator AI = Proto->arg_type_begin(),
-         AE = Proto->arg_type_end(); AI != AE; ++AI) {
-      ParmVarDecl *Param
-        = SemaRef.BuildParmVarDeclForTypedef(Function, Function->getLocation(),
-                                             *AI);
-      Param->setScopeInfo(0, Params.size());
-      Params.push_back(Param);
-    }
-  }
+  for (unsigned P = 0; P < Params.size(); ++P)
+    if (Params[P])
+      Params[P]->setOwningFunction(Function);
   Function->setParams(Params);
 
   SourceLocation InstantiateAtPOI;
@@ -1502,24 +1485,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
     return 0;
   QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo);
 
-  // \brief If the type of this function, after ignoring parentheses,
-  // is not *directly* a function type, then we're instantiating a function
-  // that was declared via a typedef, e.g.,
-  //
-  //   typedef int functype(int, int);
-  //   functype func;
-  //
-  // In this case, we'll just go instantiate the ParmVarDecls that we
-  // synthesized in the method declaration.
-  if (!isa<FunctionProtoType>(T.IgnoreParens())) {
-    assert(!Params.size() && "Instantiating type could not yield parameters");
-    SmallVector<QualType, 4> ParamTypes;
-    if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
-                               D->getNumParams(), TemplateArgs, ParamTypes,
-                               &Params))
-      return 0;
-  }
-
   NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc();
   if (QualifierLoc) {
     QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc,
@@ -2499,11 +2464,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
   if (!NewTInfo)
     return 0;
 
-  if (NewTInfo != OldTInfo) {
-    // Get parameters from the new type info.
-    TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
-    if (FunctionProtoTypeLoc OldProtoLoc =
-            OldTL.getAs<FunctionProtoTypeLoc>()) {
+  TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
+  if (FunctionProtoTypeLoc OldProtoLoc = OldTL.getAs<FunctionProtoTypeLoc>()) {
+    if (NewTInfo != OldTInfo) {
+      // Get parameters from the new type info.
       TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
       FunctionProtoTypeLoc NewProtoLoc = NewTL.castAs<FunctionProtoTypeLoc>();
       unsigned NewIdx = 0;
@@ -2533,23 +2497,45 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
           }
         }
       }
-    }
-  } else {
-    // The function type itself was not dependent and therefore no
-    // substitution occurred. However, we still need to instantiate
-    // the function parameters themselves.
-    TypeLoc OldTL = OldTInfo->getTypeLoc().IgnoreParens();
-    if (FunctionProtoTypeLoc OldProtoLoc =
-            OldTL.getAs<FunctionProtoTypeLoc>()) {
+    } else {
+      // The function type itself was not dependent and therefore no
+      // substitution occurred. However, we still need to instantiate
+      // the function parameters themselves.
+      const FunctionProtoType *OldProto =
+          cast<FunctionProtoType>(OldProtoLoc.getType());
       for (unsigned i = 0, i_end = OldProtoLoc.getNumArgs(); i != i_end; ++i) {
+        ParmVarDecl *OldParam = OldProtoLoc.getArg(i);
+        if (!OldParam) {
+          Params.push_back(SemaRef.BuildParmVarDeclForTypedef(
+              D, D->getLocation(), OldProto->getArgType(i)));
+          continue;
+        }
+
         ParmVarDecl *Parm =
-            cast_or_null<ParmVarDecl>(VisitParmVarDecl(OldProtoLoc.getArg(i)));
+            cast_or_null<ParmVarDecl>(VisitParmVarDecl(OldParam));
         if (!Parm)
           return 0;
         Params.push_back(Parm);
       }
     }
+  } else {
+    // If the type of this function, after ignoring parentheses, is not
+    // *directly* a function type, then we're instantiating a function that
+    // was declared via a typedef or with attributes, e.g.,
+    //
+    //   typedef int functype(int, int);
+    //   functype func;
+    //   int __cdecl meth(int, int);
+    //
+    // In this case, we'll just go instantiate the ParmVarDecls that we
+    // synthesized in the method declaration.
+    SmallVector<QualType, 4> ParamTypes;
+    if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
+                               D->getNumParams(), TemplateArgs, ParamTypes,
+                               &Params))
+      return 0;
   }
+
   return NewTInfo;
 }
 
index 3175af7f1b072daa807c5ddfd89903450b28413d..9e85e62cf88ecc02391af6a9149186b0064d2c38 100644 (file)
@@ -29,6 +29,8 @@ void __cdecl    free_func_default(int *);
 void __thiscall free_func_cdecl(char *);
 void __cdecl    free_func_cdecl(double);
 
+typedef void void_fun_t();
+typedef void __cdecl cdecl_fun_t();
 
 // Pointers to member functions
 struct S {
@@ -38,7 +40,13 @@ struct S {
   void __cdecl    member_cdecl2(); // expected-note {{previous declaration is here}}
   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;
+
   // Static member functions can't be __thiscall
   static void            static_member_default1();
   static void            static_member_default2(); // expected-note {{previous declaration is here}}
@@ -58,6 +66,10 @@ 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 __stdcall S::member_typedef_stdcall() {}
+
 void            S::member_cdecl1() {}
 void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thiscall' here was previously declared 'cdecl'}}
 
@@ -84,3 +96,17 @@ 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) {
+  int i;
+  for (i = 0; str[i]; i++) { }
+  return i;
+}
+extern int sse_strlen(const char *str);
+template <> inline int __cdecl mystrlen(const char *str) {
+  return sse_strlen(str);
+}
+void use_tmpl(const char *str, const int *ints) {
+  mystrlen(str);
+  mystrlen(ints);
+}
index 7ab21c7d7ed28d06950c91f6bec37d8f393c5512..5bfae537c04dbe1edb7e8fd53f1839aa3528379b 100644 (file)
@@ -81,18 +81,21 @@ namespace InstantiateFunctionTypedef {
   template<typename T>
   struct X {
     typedef int functype(int, int);
-    functype func;
+    functype func1;
+    __attribute__((noreturn)) functype func2;
 
     typedef int stdfunctype(int, int) __attribute__((stdcall));
     __attribute__((stdcall)) functype stdfunc1;
     stdfunctype stdfunc2;
 
-    // FIXME: Test a calling convention not supported by this target.
+    __attribute__((pcs("aapcs"))) functype pcsfunc; // expected-warning {{calling convention 'pcs' ignored for this target}}
   };
 
   void f(X<int> x) {
-    (void)x.func(1, 2);
+    (void)x.func1(1, 2);
+    (void)x.func2(1, 2);
     (void)x.stdfunc1(1, 2);
     (void)x.stdfunc2(1, 2);
+    (void)x.pcsfunc(1, 2);
   }
 }