VisitFunctionDecl had some logic for attempting to handle this case
which I reused for class template methods.  Instantiation still fails,
but at least now clang doesn't crash.

With AttributedTypes for these function attributes, we should be able to
make this work without losing the typedef sugar.

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

Files:
  lib/Sema/SemaTemplateInstantiate.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/decl-microsoft-call-conv.cpp
  test/SemaTemplate/instantiate-function-params.cpp
Index: lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiate.cpp
+++ lib/Sema/SemaTemplateInstantiate.cpp
@@ -1576,6 +1576,9 @@
   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())
@@ -1634,6 +1637,9 @@
                                     int indexAdjustment,
                                     Optional<unsigned> NumExpansions,
                                     bool ExpectParameterPack) {
+  if (!OldParm)
+    return 0;
+
   TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
   TypeSourceInfo *NewDI = 0;
   
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1232,26 +1232,9 @@
   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;
@@ -1501,24 +1484,6 @@
     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,
@@ -2498,57 +2463,71 @@
   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 NewTL = NewTInfo->getTypeLoc().IgnoreParens();
-      FunctionProtoTypeLoc NewProtoLoc = NewTL.castAs<FunctionProtoTypeLoc>();
-      unsigned NewIdx = 0;
-      for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc.getNumArgs();
-           OldIdx != NumOldParams; ++OldIdx) {
-        ParmVarDecl *OldParam = OldProtoLoc.getArg(OldIdx);
-        LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
-
-        Optional<unsigned> NumArgumentsInExpansion;
-        if (OldParam->isParameterPack())
-          NumArgumentsInExpansion =
-              SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
-                                                 TemplateArgs);
-        if (!NumArgumentsInExpansion) {
-          // Simple case: normal parameter, or a parameter pack that's
-          // instantiated to a (still-dependent) parameter pack.
-          ParmVarDecl *NewParam = NewProtoLoc.getArg(NewIdx++);
-          Params.push_back(NewParam);
-          Scope->InstantiatedLocal(OldParam, NewParam);
-        } else {
-          // Parameter pack expansion: make the instantiation an argument pack.
-          Scope->MakeInstantiatedLocalArgPack(OldParam);
-          for (unsigned I = 0; I != *NumArgumentsInExpansion; ++I) {
+  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;
+        for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc.getNumArgs();
+             OldIdx != NumOldParams; ++OldIdx) {
+          ParmVarDecl *OldParam = OldProtoLoc.getArg(OldIdx);
+          LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope;
+
+          Optional<unsigned> NumArgumentsInExpansion;
+          if (OldParam->isParameterPack())
+            NumArgumentsInExpansion =
+                SemaRef.getNumArgumentsInExpansion(OldParam->getType(),
+                                                   TemplateArgs);
+          if (!NumArgumentsInExpansion) {
+            // Simple case: normal parameter, or a parameter pack that's
+            // instantiated to a (still-dependent) parameter pack.
             ParmVarDecl *NewParam = NewProtoLoc.getArg(NewIdx++);
             Params.push_back(NewParam);
-            Scope->InstantiatedLocalPackArg(OldParam, NewParam);
+            Scope->InstantiatedLocal(OldParam, NewParam);
+          } else {
+            // Parameter pack expansion: make the instantiation an argument
+            // pack.
+            Scope->MakeInstantiatedLocalArgPack(OldParam);
+            for (unsigned I = 0; I != *NumArgumentsInExpansion; ++I) {
+              ParmVarDecl *NewParam = NewProtoLoc.getArg(NewIdx++);
+              Params.push_back(NewParam);
+              Scope->InstantiatedLocalPackArg(OldParam, NewParam);
+            }
           }
         }
-      }
-    }
-  } 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.
       for (unsigned i = 0, i_end = OldProtoLoc.getNumArgs(); i != i_end; ++i) {
         ParmVarDecl *Parm =
             cast_or_null<ParmVarDecl>(VisitParmVarDecl(OldProtoLoc.getArg(i)));
         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: test/SemaCXX/decl-microsoft-call-conv.cpp
===================================================================
--- test/SemaCXX/decl-microsoft-call-conv.cpp
+++ test/SemaCXX/decl-microsoft-call-conv.cpp
@@ -29,6 +29,8 @@
 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 @@
   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 @@
 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)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: test/SemaTemplate/instantiate-function-params.cpp
===================================================================
--- test/SemaTemplate/instantiate-function-params.cpp
+++ test/SemaTemplate/instantiate-function-params.cpp
@@ -81,10 +81,14 @@
   template<typename T>
   struct X {
     typedef int functype(int, int);
-    functype func;
+    functype func1;
+    __attribute__((noreturn)) functype func2;
   };
 
   void f(X<int> x) {
-    (void)x.func(1, 2);
+    (void)x.func1(1, 2);
+    // FIXME: func2 instantiation fails because we lose type location
+    // information when we adjust the function type of the typedef.
+    //(void)x.func2(1, 2);
   }
 }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to