Author: dgregor
Date: Thu Feb 9 04:18:50 2012
New Revision: 150168
URL: http://llvm.org/viewvc/llvm-project?rev=150168&view=rev
Log:
Implement return type deduction for lambdas per C++11
[expr.prim.lambda]p4, including the current suggested resolution of
core isue 975, which allows multiple return statements so long as the
types match. ExtWarn when user code is actually making use of this
extension.
Added:
cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp (with props)
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/lib/Sema/SemaLambda.cpp
cfe/trunk/test/SemaCXX/lambda-expressions.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL:
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=150168&r1=150167&r2=150168&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Feb 9 04:18:50
2012
@@ -4126,6 +4126,10 @@
def note_lambda_decl : Note<"lambda expression begins here">;
def err_lambda_unevaluated_operand : Error<
"lambda expression in an unevaluated operand">;
+def ext_lambda_implies_void_return : ExtWarn<
+ "C++11 requires lambda with omitted result type to consist of a single "
+ "return statement">,
+ InGroup<DiagGroup<"lambda-return">>;
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL:
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=150168&r1=150167&r2=150168&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Feb 9 04:18:50 2012
@@ -4185,7 +4185,7 @@
BinaryOperator *BO = dyn_cast<BinaryOperator>(E);
bool IsLogicalOperator = BO && BO->isLogicalOp();
for (Stmt::child_range I = E->children(); I; ++I) {
- Expr *ChildExpr = dyn_cast<Expr>(*I);
+ Expr *ChildExpr = dyn_cast_or_null<Expr>(*I);
if (!ChildExpr)
continue;
Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL:
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=150168&r1=150167&r2=150168&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Thu Feb 9 04:18:50 2012
@@ -294,6 +294,7 @@
bool LambdaExprNeedsCleanups;
{
LambdaScopeInfo *LSI = getCurLambda();
+ CXXMethodDecl *CallOperator = LSI->CallOperator;
Class = LSI->Lambda;
IntroducerRange = LSI->IntroducerRange;
ExplicitParams = LSI->ExplicitParams;
@@ -342,6 +343,51 @@
break;
}
+ // C++11 [expr.prim.lambda]p4:
+ // If a lambda-expression does not include a
+ // trailing-return-type, it is as if the trailing-return-type
+ // denotes the following type:
+ // FIXME: Assumes current resolution to core issue 975.
+ if (LSI->HasImplicitReturnType) {
+ // - if there are no return statements in the
+ // compound-statement, or all return statements return
+ // either an expression of type void or no expression or
+ // braced-init-list, the type void;
+ if (LSI->ReturnType.isNull()) {
+ LSI->ReturnType = Context.VoidTy;
+ } else {
+ // C++11 [expr.prim.lambda]p4:
+ // - if the compound-statement is of the form
+ //
+ // { attribute-specifier-seq[opt] return expression ; }
+ //
+ // the type of the returned expression after
+ // lvalue-to-rvalue conversion (4.1), array-to-pointer
+ // conver- sion (4.2), and function-to-pointer conversion
+ // (4.3);
+ //
+ // Since we're accepting the resolution to a post-C++11 core
+ // issue with a non-trivial extension, provide a warning (by
+ // default).
+ CompoundStmt *CompoundBody = cast<CompoundStmt>(Body);
+ if (!(CompoundBody->size() == 1 &&
+ isa<ReturnStmt>(*CompoundBody->body_begin())) &&
+ !Context.hasSameType(LSI->ReturnType, Context.VoidTy))
+ Diag(IntroducerRange.getBegin(),
+ diag::ext_lambda_implies_void_return);
+ }
+
+ // Create a function type with the inferred return type.
+ const FunctionProtoType *Proto
+ = CallOperator->getType()->getAs<FunctionProtoType>();
+ QualType FunctionTy
+ = Context.getFunctionType(LSI->ReturnType,
+ Proto->arg_type_begin(),
+ Proto->getNumArgs(),
+ Proto->getExtProtoInfo());
+ CallOperator->setType(FunctionTy);
+ }
+
// Finalize the lambda class.
SmallVector<Decl*, 4> Fields(Class->field_begin(), Class->field_end());
ActOnFields(0, Class->getLocation(), Class, Fields,
@@ -351,7 +397,6 @@
// C++ [expr.prim.lambda]p7:
// The lambda-expression's compound-statement yields the
// function-body (8.4) of the function call operator [...].
- CXXMethodDecl *CallOperator = LSI->CallOperator;
ActOnFinishFunctionBody(CallOperator, Body, /*IsInstantation=*/false);
CallOperator->setLexicalDeclContext(Class);
}
Added: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
URL:
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp?rev=150168&view=auto
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp (added)
+++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp Thu Feb 9
04:18:50 2012
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
+
+void missing_lambda_declarator() {
+ [](){}();
+}
+
+template<typename T> T get();
+
+void infer_void_return_type(int i) {
+ if (i > 17)
+ return []() { }();
+
+ if (i > 11)
+ return []() { return; }();
+
+ return [](int x) {
+ switch (x) {
+ case 0: return get<void>();
+ case 1: return;
+ }
+ }(7);
+}
+
+struct X { };
+
+X infer_X_return_type(X x) {
+ return [&x](int y) { // expected-warning{{omitted result type}}
+ if (y > 0)
+ return X();
+ else
+ return x;
+ }(5);
+}
+
+X infer_X_return_type_fail(X x) {
+ return [x](int y) { // expected-warning{{omitted result type}}
+ if (y > 0)
+ return X();
+ else // FIXME: shouldn't mention blocks
+ return x; // expected-error{{return type 'const X' must match previous
return type 'X' when block literal has unspecified explicit return type}}
+ }(5);
+}
Propchange: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cfe/trunk/test/SemaCXX/lambda-expressions.cpp
URL:
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/lambda-expressions.cpp?rev=150168&r1=150167&r2=150168&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/SemaCXX/lambda-expressions.cpp Thu Feb 9 04:18:50 2012
@@ -34,12 +34,12 @@
[](){ return 1; };
[](){ return 1; };
[](){ return ({return 1; 1;}); };
- [](){ return ({return 'c'; 1;}); }; // expected-error {{must match
previous return type}}
+ [](){ return ({return 'c'; 1;}); }; // expected-error {{must match
previous return type}} \
+ // expected-warning{{omitted result type}}
[]()->int{ return 'c'; return 1; };
[](){ return 'c'; return 1; }; // expected-error {{must match previous
return type}}
[]() { return; return (void)0; };
- // FIXME: Need to check structure of lambda body
- [](){ return 1; return 1; };
+ [](){ return 1; return 1; }; // expected-warning{{omitted result type}}
}
}
@@ -76,9 +76,11 @@
struct G { G(); G(G&); int a; }; // expected-note 6 {{not viable}}
G g;
- [=]() { const G* gg = &g; return gg->a; };
- [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; //
expected-error {{no matching constructor for initialization of 'const
ImplicitCapture::G'}}
- (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; //
expected-error 2 {{no matching constructor for initialization of 'const
ImplicitCapture::G'}}
+ [=]() { const G* gg = &g; return gg->a; }; // expected-warning{{omitted
result type}}
+ [=]() { return [=]{ const G* gg = &g; return gg->a; }(); }; //
expected-error {{no matching constructor for initialization of 'const
ImplicitCapture::G'}} \
+ // expected-warning{{omitted result type}}
+ (void)^{ return [=]{ const G* gg = &g; return gg->a; }(); }; //
expected-error 2 {{no matching constructor for initialization of 'const
ImplicitCapture::G'}} \
+ // expected-warning{{omitted result type}}
const int h = a; // expected-note {{declared}}
[]() { return h; }; // expected-error {{variable 'h' cannot be implicitly
captured in a lambda with no capture-default specified}} expected-note {{lambda
expression begins here}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits