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:
parent
2335879ff1
commit
b9657033cc
|
@ -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)) &&
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue