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;
|
||||
}
|
||||
|
||||
|
||||
// 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)) &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<int>().h(false);
|
||||
|
||||
template<typename T> 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<int>::g(); // expected-note {{in instantiation of}}
|
||||
#else
|
||||
template int U<int>::g();
|
||||
#endif
|
||||
template<typename T> auto U<T>::f() { return T(); }
|
||||
template int U<short>::g(); // ok
|
||||
}
|
||||
|
@ -408,3 +418,42 @@ namespace WithDefaultArgs {
|
|||
using T = decltype(f(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
|
||||
// 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<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 {
|
||||
void test() {
|
||||
auto L = [](auto a) -> int {
|
||||
|
|
Loading…
Reference in New Issue