Improve "assignment to cast" diagnostic.
authorDaniel Dunbar <daniel@zuster.org>
Wed, 15 Apr 2009 00:08:05 +0000 (00:08 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Wed, 15 Apr 2009 00:08:05 +0000 (00:08 +0000)
 - Strip off extra parens when looking for casts.
 - Change the location info to point at the cast (instead of the
   assignment).

For example, on

  int *b;
  #define a ((void*) b)
  void f0() {
    a = 10;
  }

we now emit:

  /tmp/t.c:4:3: error: assignment to cast is illegal, lvalue casts are not supported
    a = 10;
    ^ ~
  /tmp/t.c:2:12: note: instantiated from:
  #define a ((void*) b)
            ~^~~~~~~~~~

instead of:

  /tmp/t.c:4:5: error: expression is not assignable
    a = 10;
    ~ ^

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69114 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/AST/Expr.cpp
lib/Sema/SemaExpr.cpp
test/Sema/exprs.c

index 2102126eb641e5379565fb57fce1e5bd730933a2..ba26ef3e90202882958e444aedaa3154b4f8c1a7 100644 (file)
@@ -152,6 +152,10 @@ public:
   /// and if it is a structure or union, does not have any member (including, 
   /// recursively, any member or element of all contained aggregates or unions)
   /// with a const-qualified type.
+  ///
+  /// \param Loc [in] [out] - A source location which *may* be filled
+  /// in with the location of the expression making this a
+  /// non-modifiable lvalue, if specified.
   enum isModifiableLvalueResult {
     MLV_Valid,
     MLV_NotObjectType,
@@ -167,7 +171,8 @@ public:
     MLV_NoSetterProperty,
     MLV_MemberFunction
   };
-  isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx) const;
+  isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx,
+                                              SourceLocation *Loc = 0) const;
   
   bool isBitField();
 
index 973e662b25f63d08caa0542549053b0a62010b8c..dd346176bf0f5f0f085ca2139bd306b74473d64c 100644 (file)
@@ -756,7 +756,8 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
 /// if it is a structure or union, does not have any member (including, 
 /// recursively, any member or element of all contained aggregates or unions)
 /// with a const-qualified type.
-Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx) const {
+Expr::isModifiableLvalueResult 
+Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const {
   isLvalueResult lvalResult = isLvalue(Ctx);
     
   switch (lvalResult) {
@@ -775,9 +776,13 @@ Expr::isModifiableLvalueResult Expr::isModifiableLvalue(ASTContext &Ctx) const {
     // lvalue, then this is probably a use of the old-school "cast as lvalue"
     // GCC extension.  We don't support it, but we want to produce good
     // diagnostics when it happens so that the user knows why.
-    if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(IgnoreParens()))
-      if (CE->getSubExpr()->isLvalue(Ctx) == LV_Valid)
+    if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(IgnoreParens())) {
+      if (CE->getSubExpr()->isLvalue(Ctx) == LV_Valid) {
+        if (Loc)
+          *Loc = CE->getLParenLoc();
         return MLV_LValueCast;
+      }
+    }
     return MLV_InvalidExpression;
   case LV_MemberFunction: return MLV_MemberFunction;
   }
index 0dc3b87d524274680e3be2f26c5b1faa85d5c526..a5999cc8908c3a46ef776b1b2d05abf593e5d045 100644 (file)
@@ -3725,7 +3725,9 @@ static bool IsReadonlyProperty(Expr *E, Sema &S)
 /// 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) {
-  Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context);
+  SourceLocation OrigLoc = Loc;
+  Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context, 
+                                                              &Loc);
   if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S))
     IsLV = Expr::MLV_ReadonlyProperty;
   if (IsLV == Expr::MLV_Valid)
@@ -3769,10 +3771,13 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
     break;
   }
 
+  SourceRange Assign;
+  if (Loc != OrigLoc)
+    Assign = SourceRange(OrigLoc, OrigLoc);
   if (NeedType)
-    S.Diag(Loc, Diag) << E->getType() << E->getSourceRange();
+    S.Diag(Loc, Diag) << E->getType() << E->getSourceRange() << Assign;
   else
-    S.Diag(Loc, Diag) << E->getSourceRange();
+    S.Diag(Loc, Diag) << E->getSourceRange() << Assign; 
   return true;
 }
 
index 617eaa086cf433861a300520a7c457814938c703..d92141ce1df44f2c98e18decb05583cbfc781392 100644 (file)
@@ -34,7 +34,8 @@ void test4() {
 // rdar://6319320
 void test5(int *X, float *P) {
   (float*)X = P;   // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
-  ((float*)X) = P;   // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
+#define FOO ((float*) X)
+  FOO = P;   // expected-error {{assignment to cast is illegal, lvalue casts are not supported}}
 }
 
 void test6() {