From f45c2992a3aac7591310cd824b7c7319afd432fc Mon Sep 17 00:00:00 2001 From: Richard Smith <richard-llvm@metafoo.co.uk> Date: Sun, 12 May 2013 03:09:35 +0000 Subject: [PATCH] C++1y: provide full 'auto' return type deduction for lambda expressions. This completes the implementation of N3638. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181669 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LanguageExtensions.rst | 1 - lib/Lex/PPMacroExpansion.cpp | 2 +- lib/Sema/SemaStmt.cpp | 24 +++++++++++++++---- .../dcl.type/dcl.spec.auto/p12-1y.cpp | 17 +++++++++++++ .../expr/expr.prim/expr.prim.lambda/p4-1y.cpp | 9 +++++++ .../expr/expr.prim/expr.prim.lambda/p4.cpp | 1 + test/Lexer/has_feature_cxx0x.cpp | 10 ++++++++ www/cxx_status.html | 2 +- 8 files changed, 58 insertions(+), 8 deletions(-) create mode 100644 test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp create mode 100644 test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst index 324feafa98f..0c56d5eda77 100644 --- a/docs/LanguageExtensions.rst +++ b/docs/LanguageExtensions.rst @@ -852,7 +852,6 @@ Use ``__has_feature(cxx_return_type_deduction)`` or ``__has_extension(cxx_return_type_deduction)`` to determine if support for return type deduction for functions (using ``auto`` as a return type) is enabled. -Clang's implementation of this feature is incomplete. C++1y runtime-sized arrays ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 24c6217ced2..3abca1f1498 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -798,7 +798,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { //.Case("cxx_generalized_capture", LangOpts.CPlusPlus1y) //.Case("cxx_generic_lambda", LangOpts.CPlusPlus1y) //.Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus1y) - //.Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y) + .Case("cxx_return_type_deduction", LangOpts.CPlusPlus1y) //.Case("cxx_runtime_array", LangOpts.CPlusPlus1y) .Case("cxx_aggregate_nsdmi", LangOpts.CPlusPlus1y) //.Case("cxx_variable_templates", LangOpts.CPlusPlus1y) diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index b5ff7a30a9e..6d568c4d0b0 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2362,22 +2362,37 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, StmtResult Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // If this is the first return we've seen, infer the return type. - // [expr.prim.lambda]p4 in C++11; block literals follow a superset of those - // rules which allows multiple return statements. + // [expr.prim.lambda]p4 in C++11; block literals follow the same rules. CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); QualType FnRetType = CurCap->ReturnType; // For blocks/lambdas with implicit return types, we check each return // statement individually, and deduce the common return type when the block // or lambda is completed. - if (CurCap->HasImplicitReturnType) { + if (AutoType *AT = + FnRetType.isNull() ? 0 : FnRetType->getContainedAutoType()) { + // In C++1y, the return type may involve 'auto'. + FunctionDecl *FD = cast<LambdaScopeInfo>(CurCap)->CallOperator; + if (CurContext->isDependentContext()) { + // C++1y [dcl.spec.auto]p12: + // Return type deduction [...] occurs when the definition is + // instantiated even if the function body contains a return + // statement with a non-type-dependent operand. + CurCap->ReturnType = FnRetType = Context.DependentTy; + } else if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { + FD->setInvalidDecl(); + return StmtError(); + } else + CurCap->ReturnType = FnRetType = FD->getResultType(); + } else if (CurCap->HasImplicitReturnType) { + // FIXME: Fold this into the 'auto' codepath above. if (RetValExp && !isa<InitListExpr>(RetValExp)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp); if (Result.isInvalid()) return StmtError(); RetValExp = Result.take(); - if (!RetValExp->isTypeDependent()) + if (!CurContext->isDependentContext()) FnRetType = RetValExp->getType(); else FnRetType = CurCap->ReturnType = Context.DependentTy; @@ -2553,7 +2568,6 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); - // FIXME: Unify this and C++1y auto function handling. if (isa<CapturingScopeInfo>(getCurFunction())) return ActOnCapScopeReturnStmt(ReturnLoc, RetValExp); diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp new file mode 100644 index 00000000000..ff2abf9dfaf --- /dev/null +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p12-1y.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s +// RUN: %clang_cc1 -std=c++1y -verify %s + +template<typename T> struct S { typedef int type; }; + +template<typename T> void f() { + auto x = [] { return 0; } (); + // FIXME: We should be able to produce a 'missing typename' diagnostic here. + S<decltype(x)>::type n; // expected-error 2{{}} +} + +#if __cplusplus > 201103L +template<typename T> void g() { + auto x = [] () -> auto { return 0; } (); + S<decltype(x)>::type n; // expected-error 2{{}} +} +#endif diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp new file mode 100644 index 00000000000..79ee76f0258 --- /dev/null +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4-1y.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify + +int a; +int &b = [] (int &r) -> decltype(auto) { return r; } (a); +int &c = [] (int &r) -> decltype(auto) { return (r); } (a); +int &d = [] (int &r) -> auto & { return r; } (a); +int &e = [] (int &r) -> auto { return r; } (a); // expected-error {{cannot bind to a temporary}} +int &f = [] (int r) -> decltype(auto) { return r; } (a); // expected-error {{cannot bind to a temporary}} +int &g = [] (int r) -> decltype(auto) { return (r); } (a); // expected-warning {{reference to stack}} diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp index f580e7e4c46..368b3f695b9 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify +// RUN: %clang_cc1 -fsyntax-only -std=c++1y %s -verify void missing_lambda_declarator() { [](){}(); diff --git a/test/Lexer/has_feature_cxx0x.cpp b/test/Lexer/has_feature_cxx0x.cpp index 62a965caacb..590c168768d 100644 --- a/test/Lexer/has_feature_cxx0x.cpp +++ b/test/Lexer/has_feature_cxx0x.cpp @@ -346,3 +346,13 @@ int no_aggregate_nsdmi(); // CHECK-1Y: has_aggregate_nsdmi // CHECK-11: no_aggregate_nsdmi // CHECK-NO-11: no_aggregate_nsdmi + +#if __has_feature(cxx_return_type_deduction) +int has_return_type_deduction(); +#else +int no_return_type_deduction(); +#endif + +// CHECK-1Y: has_return_type_deduction +// CHECK-11: no_return_type_deduction +// CHECK-NO-11: no_return_type_deduction diff --git a/www/cxx_status.html b/www/cxx_status.html index ee1827ecf17..7643c7a7b1c 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -431,7 +431,7 @@ available.</p> </tr> <tr> <td>Return type deduction for normal functions</td> - <td class="partial" align="center">Partial</td> + <td class="svn" align="center">SVN</td> </tr> <tr> <td>Runtime-sized arrays with automatic storage duration</td> -- GitLab