From: Fariborz Jahanian Date: Sat, 26 Mar 2011 19:48:30 +0000 (+0000) Subject: More coherent diagnostic attempting to assign to a member of a const object returned X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=077f490d0a514dcc448475f33f799934252b85a7;p=clang More coherent diagnostic attempting to assign to a member of a const object returned from an objective-c message: // rdar://9005189 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128348 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 35264b820d..a6c3d49a2f 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -173,6 +173,7 @@ public: LV_IncompleteVoidType, LV_DuplicateVectorComponents, LV_InvalidExpression, + LV_InvalidMessageExpression, LV_MemberFunction, LV_SubObjCPropertySetting, LV_ClassTemporary @@ -204,6 +205,7 @@ public: MLV_NoSetterProperty, MLV_MemberFunction, MLV_SubObjCPropertySetting, + MLV_InvalidMessageExpression, MLV_ClassTemporary }; isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, @@ -223,6 +225,7 @@ public: CL_MemberFunction, // An expression referring to a member function CL_SubObjCPropertySetting, CL_ClassTemporary, // A prvalue of class type + CL_ObjCMessageRValue, // ObjC message is an rvalue CL_PRValue // A prvalue for any other reason, of any other type }; /// \brief The results of modification testing. diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index cee572e7a2..8ab9ff1e0b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2697,6 +2697,8 @@ def ext_gnu_ptr_func_arith : Extension< InGroup; def error_readonly_property_assignment : Error< "assigning to property with 'readonly' attribute not allowed">; +def error_readonly_message_assignment : Error< + "assigning to 'readonly' return result of an objective-c message not allowed">; def ext_integer_increment_complex : Extension< "ISO C does not support '++'/'--' on complex integer type %0">; def ext_integer_complement_complex : Extension< diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 376792223a..f90d59f505 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -75,6 +75,7 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { case Cl::CL_MemberFunction: case Cl::CL_SubObjCPropertySetting: case Cl::CL_ClassTemporary: + case Cl::CL_ObjCMessageRValue: case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; } @@ -293,7 +294,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ObjCMessageExprClass: if (const ObjCMethodDecl *Method = cast(E)->getMethodDecl()) { - return ClassifyUnnamed(Ctx, Method->getResultType()); + Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getResultType()); + return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind; } return Cl::CL_PRValue; @@ -551,6 +553,7 @@ Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const { case Cl::CL_MemberFunction: return LV_MemberFunction; case Cl::CL_SubObjCPropertySetting: return LV_SubObjCPropertySetting; case Cl::CL_ClassTemporary: return LV_ClassTemporary; + case Cl::CL_ObjCMessageRValue: return LV_InvalidMessageExpression; case Cl::CL_PRValue: return LV_InvalidExpression; } llvm_unreachable("Unhandled kind"); @@ -569,6 +572,7 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { case Cl::CL_MemberFunction: return MLV_MemberFunction; case Cl::CL_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; case Cl::CL_ClassTemporary: return MLV_ClassTemporary; + case Cl::CL_ObjCMessageRValue: return MLV_InvalidMessageExpression; case Cl::CL_PRValue: return VC.getModifiable() == Cl::CM_LValueCast ? MLV_LValueCast : MLV_InvalidExpression; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index dbddc38451..dd81b38932 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -7378,6 +7378,20 @@ static bool IsReadonlyProperty(Expr *E, Sema &S) { return false; } +static bool IsReadonlyMessage(Expr *E, Sema &S) { + if (E->getStmtClass() != Expr::MemberExprClass) + return false; + const MemberExpr *ME = cast(E); + NamedDecl *Member = ME->getMemberDecl(); + if (isa(Member)) { + Expr *Base = ME->getBase()->IgnoreParenImpCasts(); + if (Base->getStmtClass() != Expr::ObjCMessageExprClass) + return false; + return cast(Base)->getMethodDecl() != 0; + } + return false; +} + /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { @@ -7386,6 +7400,8 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { &Loc); if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S)) IsLV = Expr::MLV_ReadonlyProperty; + else if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S)) + IsLV = Expr::MLV_InvalidMessageExpression; if (IsLV == Expr::MLV_Valid) return false; @@ -7428,6 +7444,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_NoSetterProperty: Diag = diag::error_nosetter_property_assignment; break; + case Expr::MLV_InvalidMessageExpression: + Diag = diag::error_readonly_message_assignment; + break; case Expr::MLV_SubObjCPropertySetting: Diag = diag::error_no_subobject_property_setting; break; @@ -7812,7 +7831,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, ValueDecl *dcl = getPrimaryDecl(op); Expr::LValueClassification lval = op->ClassifyLValue(S.Context); - if (lval == Expr::LV_ClassTemporary) { + if (lval == Expr::LV_ClassTemporary) { bool sfinae = S.isSFINAEContext(); S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary : diag::ext_typecheck_addrof_class_temporary) diff --git a/test/SemaObjC/assign-rvalue-message.m b/test/SemaObjC/assign-rvalue-message.m new file mode 100644 index 0000000000..7e05c89afa --- /dev/null +++ b/test/SemaObjC/assign-rvalue-message.m @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s +// RUN: %clang_cc1 -x objective-c++ -triple x86_64-apple-darwin10 -fsyntax-only -verify -fobjc-nonfragile-abi %s +// rdar://9005189 + +@interface Foo +@end + +struct Bar { + int x; +}; + +@implementation Foo { + struct Bar bar; +} + +- (const struct Bar)bar { + return bar; +} + +- (void)baz { + bar.x = 0; + [self bar].x = 10; // expected-error {{assigning to 'readonly' return result of an objective-c message not allowed}} +} +@end