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.

llvm-svn: 193849
This commit is contained in:
Faisal Vali 2013-11-01 02:01:01 +00:00
parent 2335879ff1
commit b9657033cc
4 changed files with 120 additions and 6 deletions

View File

@ -109,13 +109,15 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS,
return FnD; return FnD;
} }
// In delayed template parsing mode, if we are within a class template // In delayed template parsing mode, if we are within a class template
// or if we are about to parse function member template then consume // 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. // the tokens and store them for parsing at the end of the translation unit.
if (getLangOpts().DelayedTemplateParsing && if (getLangOpts().DelayedTemplateParsing &&
DefinitionKind == FDK_Definition && DefinitionKind == FDK_Definition &&
!D.getDeclSpec().isConstexprSpecified() && !D.getDeclSpec().isConstexprSpecified() &&
!(FnD && getFunctionDecl(FnD) &&
getFunctionDecl(FnD)->getResultType()->getContainedAutoType()) &&
((Actions.CurContext->isDependentContext() || ((Actions.CurContext->isDependentContext() ||
(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
TemplateInfo.Kind != ParsedTemplateInfo::ExplicitSpecialization)) && TemplateInfo.Kind != ParsedTemplateInfo::ExplicitSpecialization)) &&

View File

@ -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 /// ParseFunctionDefinition - We parsed and verified that the specified
/// Declarator is well formed. If this is a K&R-style function, read the /// Declarator is well formed. If this is a K&R-style function, read the
/// parameters declaration-list, then start the compound-statement. /// 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. // tokens and store them for late parsing at the end of the translation unit.
if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) && if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) &&
TemplateInfo.Kind == ParsedTemplateInfo::Template && TemplateInfo.Kind == ParsedTemplateInfo::Template &&
!D.getDeclSpec().isConstexprSpecified()) { !D.getDeclSpec().isConstexprSpecified() &&
!isFunctionDeclaratorRequiringReturnTypeDeduction(D)) {
MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams); MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s // 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}} auto f(); // expected-note {{previous}}
int f(); // expected-error {{differ only in their return type}} int f(); // expected-error {{differ only in their return type}}
@ -392,10 +393,19 @@ namespace CurrentInstantiation {
int k2 = S<int>().h(false); int k2 = S<int>().h(false);
template<typename T> struct U { template<typename T> struct U {
#ifndef DELAYED_TEMPLATE_PARSING
auto f(); // expected-note {{here}} auto f(); // expected-note {{here}}
int g() { return f(); } // expected-error {{cannot be used before it is defined}} 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<int>::g(); // expected-note {{in instantiation of}} template int U<int>::g(); // expected-note {{in instantiation of}}
#else
template int U<int>::g();
#endif
template<typename T> auto U<T>::f() { return T(); } template<typename T> auto U<T>::f() { return T(); }
template int U<short>::g(); // ok template int U<short>::g(); // ok
} }
@ -408,3 +418,42 @@ namespace WithDefaultArgs {
using T = decltype(f(A<int>())); using T = decltype(f(A<int>()));
using T = decltype(f<int>(A<int>())); using T = decltype(f<int>(A<int>()));
} }
namespace MultilevelDeduction {
auto F() -> auto* { return (int*)0; }
auto (*G())() -> int* { return F; }
auto run = G();
namespace Templated {
template<class T>
auto F(T t) -> auto* { return (T*)0; }
template<class T>
auto (*G(T t))(T) -> T* { return &F<T>; }
template<class T>
auto (*G2(T t))(T) -> auto* { return &F<T>; }
auto run_int = G(1);
auto run_char = G2('a');
}
}
namespace rnk {
extern "C" int puts(const char *s);
template <typename T>
auto foo(T x) -> decltype(x) {
#ifdef DELAYED_TEMPLATE_PARSING
::rnk::bar();
#endif
return x;
}
void bar() { puts("bar"); }
int main() { return foo(0); }
}

View File

@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only -fblocks -emit-llvm-only %s // 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 // RUN: %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 // RUN: %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 -fms-extensions %s -DMS_EXTENSIONS -DDELAYED_TEMPLATE_PARSING
namespace explicit_call { namespace explicit_call {
int test() { 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 } //end at_ns_scope_within_class_member
namespace at_ns_scope_within_class_template_member {
struct X {
static void foo(double d) { }
template<class T = int>
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 { namespace nested_generic_lambdas_123 {
void test() { void test() {
auto L = [](auto a) -> int { auto L = [](auto a) -> int {