From: Eli Friedman Date: Fri, 14 Jun 2013 21:14:10 +0000 (+0000) Subject: Unify return type checking for functions and ObjC methods. Move all the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ddb5a3926d715ab4354ca36117679e3f4d5d3e21;p=clang Unify return type checking for functions and ObjC methods. Move all the random checks for ObjC object return types to SemaType.cpp. Fixes issue with ObjC method type checking reported on cfe-dev. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184006 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index d014a9dcb3..7891f12323 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4926,8 +4926,6 @@ let CategoryName = "Lambda Issue" in { "lambda expression in default argument cannot capture any entity">; 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_noreturn_lambda_has_return_expr : Error< "lambda declared 'noreturn' should not return">; def warn_maybe_falloff_nonvoid_lambda : Warning< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 117a519fb6..9a91bc46d7 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1003,6 +1003,8 @@ public: QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); + bool CheckFunctionReturnType(QualType T, SourceLocation Loc); + /// \brief Build a function type. /// /// This routine checks the function type according to C++ rules and diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index e43a318804..f0d9fe8baa 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5896,23 +5896,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); - // Do not allow returning a objc interface by-value. - if (R->getAs()->getResultType()->isObjCObjectType()) { - Diag(D.getIdentifierLoc(), - diag::err_object_cannot_be_passed_returned_by_value) << 0 - << R->getAs()->getResultType() - << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*"); - - QualType T = R->getAs()->getResultType(); - T = Context.getObjCObjectPointerType(T); - if (const FunctionProtoType *FPT = dyn_cast(R)) { - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - R = Context.getFunctionType(T, FPT->getArgTypes(), EPI); - } - else if (isa(R)) - R = Context.getFunctionNoProtoType(T); - } - bool isFriend = false; FunctionTemplateDecl *FunctionTemplate = 0; bool isExplicitSpecialization = false; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 21d66d0497..07282935c8 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -3009,14 +3009,9 @@ Decl *Sema::ActOnMethodDeclaration( if (ReturnType) { resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo); - // Methods cannot return interface types. All ObjC objects are - // passed by reference. - if (resultDeclType->isObjCObjectType()) { - Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value) - << 0 << resultDeclType; + if (CheckFunctionReturnType(resultDeclType, MethodLoc)) return 0; - } - + HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType()); } else { // get the type for "id". resultDeclType = Context.getObjCIdType(); @@ -3099,14 +3094,8 @@ Decl *Sema::ActOnMethodDeclaration( else // Perform the default array/function conversions (C99 6.7.5.3p[7,8]). ArgType = Context.getAdjustedParameterType(ArgType); - if (ArgType->isObjCObjectType()) { - Diag(Param->getLocation(), - diag::err_object_cannot_be_passed_returned_by_value) - << 1 << ArgType; - Param->setInvalidDecl(); - } + Param->setDeclContext(ObjCMethod); - Params.push_back(Param); } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index a6473a1c5c..edeb731b83 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -9887,13 +9887,6 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, CurBlock->TheDecl->setIsVariadic(isVariadic); - // Don't allow returning a objc interface by value. - if (RetTy->isObjCObjectType()) { - Diag(ParamInfo.getLocStart(), - diag::err_object_cannot_be_passed_returned_by_value) << 0 << RetTy; - return; - } - // Context.DependentTy is used as a placeholder for a missing block // return type. TODO: what should we do with declarators like: // ^ * { ... } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index d8e90e5cb5..32cc176119 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -194,9 +194,6 @@ LambdaScopeInfo *Sema::enterLambdaScope(CXXMethodDecl *CallOperator, 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 { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 99beabeda9..279a6e3482 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -33,6 +33,8 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" +#include "TypeLocBuilder.h" + using namespace clang; /// isOmittedBlockReturnType - Return true if this declarator is missing a @@ -1654,24 +1656,38 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc); } -QualType Sema::BuildFunctionType(QualType T, - llvm::MutableArrayRef ParamTypes, - SourceLocation Loc, DeclarationName Entity, - const FunctionProtoType::ExtProtoInfo &EPI) { +bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { if (T->isArrayType() || T->isFunctionType()) { Diag(Loc, diag::err_func_returning_array_function) << T->isFunctionType() << T; - return QualType(); + return true; } // Functions cannot return half FP. if (T->isHalfType()) { Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << FixItHint::CreateInsertion(Loc, "*"); - return QualType(); + return true; + } + + // Methods cannot return interface types. All ObjC objects are + // passed by reference. + if (T->isObjCObjectType()) { + Diag(Loc, diag::err_object_cannot_be_passed_returned_by_value) << 0 << T; + return 0; } + return false; +} + +QualType Sema::BuildFunctionType(QualType T, + llvm::MutableArrayRef ParamTypes, + SourceLocation Loc, DeclarationName Entity, + const FunctionProtoType::ExtProtoInfo &EPI) { bool Invalid = false; + + Invalid |= CheckFunctionReturnType(T, Loc); + for (unsigned Idx = 0, Cnt = ParamTypes.size(); Idx < Cnt; ++Idx) { // FIXME: Loc is too inprecise here, should use proper locations for args. QualType ParamType = Context.getAdjustedParameterType(ParamTypes[Idx]); @@ -2682,6 +2698,33 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + // Methods cannot return interface types. All ObjC objects are + // passed by reference. + if (T->isObjCObjectType()) { + SourceLocation DiagLoc, FixitLoc; + if (TInfo) { + DiagLoc = TInfo->getTypeLoc().getLocStart(); + FixitLoc = S.PP.getLocForEndOfToken(TInfo->getTypeLoc().getLocEnd()); + } else { + DiagLoc = D.getDeclSpec().getTypeSpecTypeLoc(); + FixitLoc = S.PP.getLocForEndOfToken(D.getDeclSpec().getLocEnd()); + } + S.Diag(DiagLoc, diag::err_object_cannot_be_passed_returned_by_value) + << 0 << T + << FixItHint::CreateInsertion(FixitLoc, "*"); + + T = Context.getObjCObjectPointerType(T); + if (TInfo) { + TypeLocBuilder TLB; + TLB.pushFullCopy(TInfo->getTypeLoc()); + ObjCObjectPointerTypeLoc TLoc = TLB.push(T); + TLoc.setStarLoc(FixitLoc); + TInfo = TLB.getTypeSourceInfo(Context, T); + } + + D.setInvalidType(true); + } + // cv-qualifiers on return types are pointless except when the type is a // class type in C++. if ((T.getCVRQualifiers() || T->isAtomicType()) && diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index da1e41c2af..1fd206bbc2 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -8986,15 +8986,6 @@ TreeTransform::TransformBlockExpr(BlockExpr *E) { QualType exprResultType = getDerived().TransformType(exprFunctionType->getResultType()); - // Don't allow returning a objc interface by value. - if (exprResultType->isObjCObjectType()) { - getSema().Diag(E->getCaretLocation(), - diag::err_object_cannot_be_passed_returned_by_value) - << 0 << exprResultType; - getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/0); - return ExprError(); - } - QualType functionType = getDerived().RebuildFunctionProtoType(exprResultType, paramTypes, exprFunctionType->getExtProtoInfo()); diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm index 0126e23a74..92c62904d5 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm @@ -4,5 +4,5 @@ @end void test_result_type() { - auto l1 = [] () -> A { }; // expected-error{{non-pointer Objective-C class type 'A' in lambda expression result}} + auto l1 = [] () -> A { }; // expected-error{{interface type 'A' cannot be returned by value; did you forget * in 'A'?}} } diff --git a/test/CodeGenObjC/blocks.m b/test/CodeGenObjC/blocks.m index 3718ad590a..d872e17051 100644 --- a/test/CodeGenObjC/blocks.m +++ b/test/CodeGenObjC/blocks.m @@ -7,7 +7,7 @@ struct S { @interface T - - (int)foo: (T (^)(T*)) x; + - (int)foo: (T* (^)(T*)) x; @end void foo(T *P) { diff --git a/test/FixIt/fixit-static-object-decl.m b/test/FixIt/fixit-static-object-decl.m index e13900fa78..5f4feada49 100644 --- a/test/FixIt/fixit-static-object-decl.m +++ b/test/FixIt/fixit-static-object-decl.m @@ -5,8 +5,8 @@ // Objective-C++ recovery // RUN: cp %s %t -// RUN: not %clang_cc1 -fixit -x objective-c++ %t -// RUN: %clang_cc1 -fsyntax-only -Werror -x objective-c++ %t +// RUN: not %clang_cc1 -fixit -x objective-c++ %t -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -Werror -x objective-c++ %t -std=c++11 // rdar://9603056 @interface S @end @@ -24,6 +24,14 @@ NSArray func() { return P; } +NSArray (func2)() { return 0; } + +#ifdef __cplusplus +void test_result_type() { + auto l1 = [] () -> NSArray { return 0; }; +} +#endif + int main() { NSArray pluginNames = [NSArray arrayWithObjects]; } diff --git a/test/SemaObjC/method-bad-param.m b/test/SemaObjC/method-bad-param.m index d44b53614a..30aba7b9d0 100644 --- a/test/SemaObjC/method-bad-param.m +++ b/test/SemaObjC/method-bad-param.m @@ -42,3 +42,7 @@ enum bogus; // expected-note {{forward declaration of 'enum bogus'}} } @end +@interface arrayfun +- (int[6])arrayRet; // expected-error {{function cannot return array type 'int [6]'}} +- (int())funcRet; // expected-error {{function cannot return function type 'int ()'}} +@end