From 53393f23d8b767f976427a6d45b310bf37dd91c4 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 14 Feb 2012 21:20:44 +0000 Subject: [PATCH] Check the return type of lambda expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150503 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 83 ++++++++++--------- lib/Sema/SemaLambda.cpp | 17 +++- .../expr/expr.prim/expr.prim.lambda/p4.cpp | 8 ++ .../CXX/expr/expr.prim/expr.prim.lambda/p4.mm | 8 ++ 4 files changed, 74 insertions(+), 42 deletions(-) create mode 100644 test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ba7e63ab80..f76dcc2bad 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3999,44 +3999,51 @@ def err_throw_incomplete_ptr : Error< def err_return_in_constructor_handler : Error< "return in the catch of a function try block of a constructor is illegal">; -def err_capture_more_than_once : Error< - "%0 can appear only once in a capture list">; -def err_reference_capture_with_reference_default : Error< - "'&' cannot precede a capture when the capture default is '&'">; -def err_this_capture_with_copy_default : Error< - "'this' cannot be explicitly captured when the capture default is '='">; -def err_copy_capture_with_copy_default : Error< - "'&' must precede a capture when the capture default is '='">; -def err_capture_does_not_name_variable : Error< - "%0 in capture list does not name a variable">; -def err_capture_non_automatic_variable : Error< - "%0 cannot be captured because it does not have automatic storage duration">; -def err_this_capture : Error< - "'this' cannot be %select{implicitly |}0captured in this context">; -def err_lambda_capture_block : Error< - "__block variable %0 cannot be captured in a lambda expression">; -def err_lambda_capture_anonymous_var : Error< - "unnamed variable cannot be implicitly captured in a lambda expression">; -def err_lambda_capture_vm_type : Error< - "variable %0 with variably modified type cannot be captured in " - "a lambda expression">; -def err_lambda_impcap : Error< - "variable %0 cannot be implicitly captured in a lambda with no " - "capture-default specified">; -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>; -def err_lambda_return_init_list : Error< - "cannot deduce lambda return type from initializer list">; -def err_lambda_capture_default_arg : Error< - "lambda expression in default argument cannot capture any entity">; -def err_lambda_unexpanded_pack : Error< - "unexpanded function parameter pack capture is unsupported">; - +let CategoryName = "Lambda Issue" in { + def err_capture_more_than_once : Error< + "%0 can appear only once in a capture list">; + def err_reference_capture_with_reference_default : Error< + "'&' cannot precede a capture when the capture default is '&'">; + def err_this_capture_with_copy_default : Error< + "'this' cannot be explicitly captured when the capture default is '='">; + def err_copy_capture_with_copy_default : Error< + "'&' must precede a capture when the capture default is '='">; + def err_capture_does_not_name_variable : Error< + "%0 in capture list does not name a variable">; + def err_capture_non_automatic_variable : Error< + "%0 cannot be captured because it does not have automatic storage " + "duration">; + def err_this_capture : Error< + "'this' cannot be %select{implicitly |}0captured in this context">; + def err_lambda_capture_block : Error< + "__block variable %0 cannot be captured in a lambda expression">; + def err_lambda_capture_anonymous_var : Error< + "unnamed variable cannot be implicitly captured in a lambda expression">; + def err_lambda_capture_vm_type : Error< + "variable %0 with variably modified type cannot be captured in " + "a lambda expression">; + def err_lambda_impcap : Error< + "variable %0 cannot be implicitly captured in a lambda with no " + "capture-default specified">; + 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>; + def err_lambda_return_init_list : Error< + "cannot deduce lambda return type from initializer list">; + def err_lambda_capture_default_arg : Error< + "lambda expression in default argument cannot capture any entity">; + def err_lambda_unexpanded_pack : Error< + "unexpanded function parameter pack capture is unsupported">; + def err_lambda_incomplete_result : Error< + "incomplete result type %0 in lambda expression">; + def err_lambda_objc_object_result : Error< + "non-pointer Objective-C class type %0 in lambda expression result">; +} + def err_operator_arrow_circular : Error< "circular pointer delegation detected">; def err_pseudo_dtor_base_not_scalar : Error< diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index c75c3c5b7d..8b8a083a06 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -87,6 +87,17 @@ LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator, if (ExplicitResultType) { LSI->ReturnType = CallOperator->getResultType(); + + if (!LSI->ReturnType->isDependentType() && + !LSI->ReturnType->isVoidType()) { + if (RequireCompleteType(CallOperator->getLocStart(), LSI->ReturnType, + diag::err_lambda_incomplete_result)) { + // Do nothing. + } else if (LSI->ReturnType->isObjCObjectOrInterfaceType()) { + Diag(CallOperator->getLocStart(), diag::err_lambda_objc_object_result) + << LSI->ReturnType; + } + } } else { LSI->HasImplicitReturnType = true; } @@ -161,7 +172,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, CheckExtraCXXDefaultArguments(ParamInfo); MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); - // FIXME: Can these asserts actually fail? assert(MethodTyInfo && "no type from lambda-declarator"); EndLoc = ParamInfo.getSourceRange().getEnd(); @@ -266,7 +276,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // for unqualified name lookup (3.4.1); each such lookup shall find a // variable with automatic storage duration declared in the reaching // scope of the local lambda expression. - // FIXME: Check reaching scope. + // + // Note that the 'reaching scope' check happens in TryCaptureVar. VarDecl *Var = R.getAsSingle(); if (!Var) { Diag(C->Loc, diag::err_capture_does_not_name_variable) << C->Id; @@ -321,8 +332,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, addLambdaParameters(Method, CurScope, Proto.getParams()); } - // FIXME: Check return type is complete, !isObjCObjectType - // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. PushExpressionEvaluationContext(PotentiallyEvaluated); 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 cff0c09950..586825f053 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp @@ -41,3 +41,11 @@ X infer_X_return_type_fail(X x) { return x; // expected-error{{return type 'const X' must match previous return type 'X' when block literal has unspecified explicit return type}} }(5); } + +struct Incomplete; // expected-note{{forward declaration of 'Incomplete'}} +void test_result_type(int N) { + auto l1 = [] () -> Incomplete { }; // expected-error{{incomplete result type 'Incomplete' in lambda expression}} + + typedef int vla[N]; + auto l2 = [] () -> vla { }; // expected-error{{function cannot return array type 'vla' (aka 'int [N]')}} +} diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm new file mode 100644 index 0000000000..0126e23a74 --- /dev/null +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify + +@interface A +@end + +void test_result_type() { + auto l1 = [] () -> A { }; // expected-error{{non-pointer Objective-C class type 'A' in lambda expression result}} +} -- 2.40.0