diff options
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 90 | ||||
-rw-r--r-- | clang/test/SemaCXX/decl-microsoft-call-conv.cpp | 28 | ||||
-rw-r--r-- | clang/test/SemaTemplate/instantiate-function-params.cpp | 9 |
4 files changed, 74 insertions, 56 deletions
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 67b53b4c0a7..57eb64d127a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -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()) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index ffd7645f713..52075229971 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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; } diff --git a/clang/test/SemaCXX/decl-microsoft-call-conv.cpp b/clang/test/SemaCXX/decl-microsoft-call-conv.cpp index 3175af7f1b0..9e85e62cf88 100644 --- a/clang/test/SemaCXX/decl-microsoft-call-conv.cpp +++ b/clang/test/SemaCXX/decl-microsoft-call-conv.cpp @@ -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); +} diff --git a/clang/test/SemaTemplate/instantiate-function-params.cpp b/clang/test/SemaTemplate/instantiate-function-params.cpp index 7ab21c7d7ed..5bfae537c04 100644 --- a/clang/test/SemaTemplate/instantiate-function-params.cpp +++ b/clang/test/SemaTemplate/instantiate-function-params.cpp @@ -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); } } |