]> granicus.if.org Git - clang/commitdiff
Unify return type checking for functions and ObjC methods. Move all the
authorEli Friedman <eli.friedman@gmail.com>
Fri, 14 Jun 2013 21:14:10 +0000 (21:14 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 14 Jun 2013 21:14:10 +0000 (21:14 +0000)
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

12 files changed:
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaType.cpp
lib/Sema/TreeTransform.h
test/CXX/expr/expr.prim/expr.prim.lambda/p4.mm
test/CodeGenObjC/blocks.m
test/FixIt/fixit-static-object-decl.m
test/SemaObjC/method-bad-param.m

index d014a9dcb3837697249da66121e6e32b5d4fcc40..7891f12323e2797471a9c47e565e9aceca676393 100644 (file)
@@ -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<
index 117a519fb63ae56ff0bd0b7a709f279e8f6c7837..9a91bc46d7ba9e3d4a87f141e66b8688c6f1d40e 100644 (file)
@@ -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
index e43a318804d21ee825f383d290e25518eadb5731..f0d9fe8baaeb7a329d7f2fd639e6167c3169ccdc 100644 (file)
@@ -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<FunctionType>()->getResultType()->isObjCObjectType()) {
-    Diag(D.getIdentifierLoc(),
-         diag::err_object_cannot_be_passed_returned_by_value) << 0
-    << R->getAs<FunctionType>()->getResultType()
-    << FixItHint::CreateInsertion(D.getIdentifierLoc(), "*");
-
-    QualType T = R->getAs<FunctionType>()->getResultType();
-    T = Context.getObjCObjectPointerType(T);
-    if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(R)) {
-      FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
-      R = Context.getFunctionType(T, FPT->getArgTypes(), EPI);
-    }
-    else if (isa<FunctionNoProtoType>(R))
-      R = Context.getFunctionNoProtoType(T);
-  }
-
   bool isFriend = false;
   FunctionTemplateDecl *FunctionTemplate = 0;
   bool isExplicitSpecialization = false;
index 21d66d0497633a07f4450ac729c309255a4ee4d8..07282935c8a446cf7607be7ea57644c14b438c5b 100644 (file)
@@ -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);
   }
   
index a6473a1c5c4c3eee2cbdb8e0e6fc8b1db7162e09..edeb731b83df367ebbc01218c26b3c062af2ffdd 100644 (file)
@@ -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:
   //   ^ * { ... }
index d8e90e5cb58ddad2758138c8d4418b5143105c4c..32cc176119d4cd45abea094b9f4e32dc45e53b67 100644 (file)
@@ -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 {
index 99beabeda9bacec14f11b4e075419ae4e85fd1c8..279a6e348232fc9987e40fa5ee9820b7c4c48abf 100644 (file)
@@ -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<QualType> 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<QualType> 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<ObjCObjectPointerTypeLoc>(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()) &&
index da1e41c2afbd6406c5ce3ff8e5dbece735d5891f..1fd206bbc20828e850f6c1fb2be78e6c86d92f3c 100644 (file)
@@ -8986,15 +8986,6 @@ TreeTransform<Derived>::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());
index 0126e23a74abb8ebcff547640c1a22cd8b9899f6..92c62904d57b2a869af2464eb4955197ffb01ca7 100644 (file)
@@ -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'?}}
 }
index 3718ad590a53933887c7fcd57c7eb942c00efb41..d872e17051bdf57e4c209d489a5932047dbc96d0 100644 (file)
@@ -7,7 +7,7 @@ struct S {
 
 
 @interface T
-  - (int)foo: (T (^)(T*)) x;
+  - (int)foo: (T* (^)(T*)) x;
 @end
 
 void foo(T *P) {
index e13900fa786f483a6ffc218e3938ee18d70e8d33..5f4feada4905ad35898a348a303449422accad40 100644 (file)
@@ -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];
 }
index d44b53614aa4aaff9a6874e61bab06c721bd78d7..30aba7b9d0de7d5da0e425221f920a8eef589688 100644 (file)
@@ -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