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.

llvm-svn: 184006
This commit is contained in:
Eli Friedman 2013-06-14 21:14:10 +00:00
parent ab2436ee83
commit 31a5bcc24e
12 changed files with 70 additions and 62 deletions

View 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<

View 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

View 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;

View 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);
}

View 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:
// ^ * { ... }

View 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 {

View 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()) &&

View 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());

View 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'?}}
}

View File

@ -7,7 +7,7 @@ struct S {
@interface T
- (int)foo: (T (^)(T*)) x;
- (int)foo: (T* (^)(T*)) x;
@end
void foo(T *P) {

View 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];
}

View 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