[cfe-commits] [PATCH] CallExprs returning references can be lvalues

Jordy Rose jediknil at belkadan.com
Wed Jun 2 15:20:45 PDT 2010


Revised patch without the section that was completely commented out. Oops.

On Wed, 02 Jun 2010 15:19:25 -0700, Jordy Rose <jediknil at belkadan.com>
wrote:
> Fixes a crasher, by allowing CallExprs to be lvalues, and making sure
> assignment LHSes are treated as lvalues.
> 
> char& ref();
> void t5 () {
>   ref() = 'c';
> }
> 
> And an incorrect "undefined dereference" warning, by noting that
assigning
> to a reference variable does not kill its value.
> 
> char t1 () {
>   char& r = ref();
>   r = 'c'; // no-warning
>   if (r) return r;
>   return *(char*)0; // no-warning
> }
-------------- next part --------------
Index: lib/Analysis/CFG.cpp
===================================================================
--- lib/Analysis/CFG.cpp	(revision 105255)
+++ lib/Analysis/CFG.cpp	(working copy)
@@ -538,6 +538,15 @@
     addStmt(B->getRHS());
     return addStmt(B->getLHS());
   }
+  else if (B->isAssignmentOp()) {
+    if (asc.alwaysAdd()) {
+      autoCreateBlock();
+      AppendStmt(Block, B, asc);
+    }
+    
+    addStmt(B->getRHS());
+    return addStmt(B->getLHS(), AddStmtChoice::AsLValueNotAlwaysAdd);
+  }
 
   return VisitStmt(B, asc);
 }
@@ -612,8 +621,12 @@
   if (!CanThrow(C->getCallee()))
     AddEHEdge = false;
 
-  if (!NoReturn && !AddEHEdge)
-    return VisitStmt(C, AddStmtChoice::AlwaysAdd);
+  if (!NoReturn && !AddEHEdge) {
+    if (asc.asLValue())
+      return VisitStmt(C, AddStmtChoice::AlwaysAddAsLValue);
+    else
+      return VisitStmt(C, AddStmtChoice::AlwaysAdd);
+  }
 
   if (Block) {
     Succ = Block;
Index: lib/Analysis/LiveVariables.cpp
===================================================================
--- lib/Analysis/LiveVariables.cpp	(revision 105255)
+++ lib/Analysis/LiveVariables.cpp	(working copy)
@@ -256,17 +256,21 @@
 
   // Assigning to a variable?
   if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParens())) {
+    // Assignments to references don't kill the ref's address
+    if (DR->getDecl()->getType()->isReferenceType()) {
+      VisitDeclRefExpr(DR);
+    } else {
+      // Update liveness inforamtion.
+      unsigned bit = AD.getIdx(DR->getDecl());
+      LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
 
-    // Update liveness inforamtion.
-    unsigned bit = AD.getIdx(DR->getDecl());
-    LiveState.getDeclBit(bit) = Dead | AD.AlwaysLive.getDeclBit(bit);
+      if (AD.Observer) { AD.Observer->ObserverKill(DR); }
 
-    if (AD.Observer) { AD.Observer->ObserverKill(DR); }
-
-    // Handle things like +=, etc., which also generate "uses"
-    // of a variable.  Do this just by visiting the subexpression.
-    if (B->getOpcode() != BinaryOperator::Assign)
-      VisitDeclRefExpr(DR);
+      // Handle things like +=, etc., which also generate "uses"
+      // of a variable.  Do this just by visiting the subexpression.
+      if (B->getOpcode() != BinaryOperator::Assign)
+        VisitDeclRefExpr(DR);
+    }
   }
   else // Not assigning to a variable.  Process LHS as usual.
     Visit(LHS);
Index: test/Analysis/reference.cpp
===================================================================
--- test/Analysis/reference.cpp	(revision 105255)
+++ test/Analysis/reference.cpp	(working copy)
@@ -9,3 +9,48 @@
   if (b != 3)
     *p = 1; // no-warning
 }
+
+typedef typeof(sizeof(int)) size_t;
+void malloc (size_t);
+
+char* ptr();
+char& ref();
+
+// Each of the tests below is repeated with pointers as well as references.
+// This is mostly a sanity check, but then again, both should work!
+char t1 () {
+  char& r = ref();
+  r = 'c'; // no-warning
+  if (r) return r;
+  return *(char*)0; // no-warning
+}
+
+char t2 () {
+  char* p = ptr();
+  *p = 'c'; // no-warning
+  if (*p) return *p;
+  return *(char*)0; // no-warning
+}
+
+char t3 (char& r) {
+  r = 'c'; // no-warning
+  if (r) return r;
+  return *(char*)0; // no-warning
+}
+
+char t4 (char* p) {
+  *p = 'c'; // no-warning
+  if (*p) return *p;
+  return *(char*)0; // no-warning
+}
+
+// These next two tests just shouldn't crash.
+char t5 () {
+  ref() = 'c';
+  return '0';
+}
+
+char t6 () {
+  *ptr() = 'c';
+  return '0';
+}


More information about the cfe-commits mailing list