From: Faisal Vali Date: Fri, 1 Nov 2013 02:01:01 +0000 (+0000) Subject: Support return type deduction for templates in -fdelayed-template-parsing (microsoft... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=32b5ca012c42d418c9ff0d4175b17f174459e187;p=clang Support return type deduction for templates in -fdelayed-template-parsing (microsoft) mode Please see http://llvm-reviews.chandlerc.com/D2053 for discussion and Richard's stamp. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193849 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 863a09e89d..0c8ace59e3 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -109,13 +109,15 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, return FnD; } - + // In delayed template parsing mode, if we are within a class template // or if we are about to parse function member template then consume // the tokens and store them for parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && DefinitionKind == FDK_Definition && - !D.getDeclSpec().isConstexprSpecified() && + !D.getDeclSpec().isConstexprSpecified() && + !(FnD && getFunctionDecl(FnD) && + getFunctionDecl(FnD)->getResultType()->getContainedAutoType()) && ((Actions.CurContext->isDependentContext() || (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && TemplateInfo.Kind != ParsedTemplateInfo::ExplicitSpecialization)) && diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index d95546af8a..84aad4101f 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -919,6 +919,26 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributesWithRange &attrs, } } + +static inline bool isFunctionDeclaratorRequiringReturnTypeDeduction( + const Declarator &D) { + if (!D.isFunctionDeclarator() || !D.getDeclSpec().containsPlaceholderType()) + return false; + for (unsigned I = 0, E = D.getNumTypeObjects(); I != E; ++I) { + unsigned chunkIndex = E - I - 1; + const DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); + if (DeclType.Kind == DeclaratorChunk::Function) { + const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; + if (!FTI.hasTrailingReturnType()) + return true; + QualType TrailingRetType = FTI.getTrailingReturnType().get(); + return TrailingRetType->getCanonicalTypeInternal() + ->getContainedAutoType(); + } + } + return false; +} + /// ParseFunctionDefinition - We parsed and verified that the specified /// Declarator is well formed. If this is a K&R-style function, read the /// parameters declaration-list, then start the compound-statement. @@ -992,7 +1012,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // tokens and store them for late parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) && TemplateInfo.Kind == ParsedTemplateInfo::Template && - !D.getDeclSpec().isConstexprSpecified()) { + !D.getDeclSpec().isConstexprSpecified() && + !isFunctionDeclaratorRequiringReturnTypeDeduction(D)) { MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams); ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); diff --git a/test/SemaCXX/cxx1y-deduced-return-type.cpp b/test/SemaCXX/cxx1y-deduced-return-type.cpp index 9e779bf170..3e19cb57f3 100644 --- a/test/SemaCXX/cxx1y-deduced-return-type.cpp +++ b/test/SemaCXX/cxx1y-deduced-return-type.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING auto f(); // expected-note {{previous}} int f(); // expected-error {{differ only in their return type}} @@ -392,10 +393,19 @@ namespace CurrentInstantiation { int k2 = S().h(false); template struct U { + #ifndef DELAYED_TEMPLATE_PARSING auto f(); // expected-note {{here}} int g() { return f(); } // expected-error {{cannot be used before it is defined}} + #else + auto f(); + int g() { return f(); } + #endif }; + #ifndef DELAYED_TEMPLATE_PARSING template int U::g(); // expected-note {{in instantiation of}} + #else + template int U::g(); + #endif template auto U::f() { return T(); } template int U::g(); // ok } @@ -408,3 +418,42 @@ namespace WithDefaultArgs { using T = decltype(f(A())); using T = decltype(f(A())); } + +namespace MultilevelDeduction { + +auto F() -> auto* { return (int*)0; } + +auto (*G())() -> int* { return F; } + +auto run = G(); + +namespace Templated { +template +auto F(T t) -> auto* { return (T*)0; } + +template +auto (*G(T t))(T) -> T* { return &F; } + + +template +auto (*G2(T t))(T) -> auto* { return &F; } + +auto run_int = G(1); +auto run_char = G2('a'); + +} +} + +namespace rnk { +extern "C" int puts(const char *s); +template +auto foo(T x) -> decltype(x) { +#ifdef DELAYED_TEMPLATE_PARSING + ::rnk::bar(); +#endif + return x; +} +void bar() { puts("bar"); } +int main() { return foo(0); } + +} diff --git a/test/SemaCXX/cxx1y-generic-lambdas.cpp b/test/SemaCXX/cxx1y-generic-lambdas.cpp index 93d7a83500..a7ec6755d6 100644 --- a/test/SemaCXX/cxx1y-generic-lambdas.cpp +++ b/test/SemaCXX/cxx1y-generic-lambdas.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s -// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING -// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS -// DONTRUNYET: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing %s -DDELAYED_TEMPLATE_PARSING +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fms-extensions %s -DMS_EXTENSIONS +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -fdelayed-template-parsing -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING namespace explicit_call { int test() { @@ -572,6 +572,48 @@ int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expe } //end at_ns_scope_within_class_member +namespace at_ns_scope_within_class_template_member { + struct X { + static void foo(double d) { } + template + auto test(T = T{}) { + auto L = [](auto a) { + print("a = ", a, "\n"); + foo(a); + return [](decltype(a) b) { + foo(b); + foo(sizeof(a) + sizeof(b)); + return [](auto ... c) { + print("c = ", c ..., "\n"); + foo(decltype(b){}); + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*)); + return [](decltype(c) ... d) ->decltype(a) { //expected-note{{candidate}} + print("d = ", d ..., "\n"); + foo(decltype(b){}); + foo(sizeof(decltype(a)*) + sizeof(decltype(b)*)); + return decltype(a){}; + }; + }; + }; + }; + return L; + } + +}; +X x; +auto L = x.test(); +auto L_test = L('4'); +auto M = L('3'); +auto M_test = M('a'); +auto N = M('x'); +auto O = N("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456); +char (*np)(const char*, int, const char*, double, const char*, int) = O; +auto NP_result = np("\n3 = ", 3, "\n6.14 = ", 6.14, "\n4'123'456 = ", 4'123'456); +int (*np2)(const char*, int, const char*, double, const char*, int) = O; // expected-error{{no viable conversion}} + +} //end at_ns_scope_within_class_member + + namespace nested_generic_lambdas_123 { void test() { auto L = [](auto a) -> int {