On Jun 8, 2012, at 5:47 PM, Richard Trieu wrote:
> On Fri, Jun 8, 2012 at 4:29 PM, John McCall <[email protected]> wrote:
> On Jun 8, 2012, at 4:24 PM, Richard Trieu wrote:
> > Add a bit to VarDecl that is set to true when its address is taken or it 
> > gets passed by non-const reference.
> 
> Just out of curiosity, is this bit set for variables of class type that are 
> used as an operand of a trivial copy constructor or copy assignment operator?
> 
> John.
> 
> No, the bit is not currently set for those uses.

Then please document the desired semantics more accurately, like "the address 
is taken or bound to a reference other than either operand of a trivial copy 
operation" or whatever semantics we actually settle on.

Please document that this is only accurate when all possible accesses have been 
seen.  For example, it is only accurate for local variables after their scope 
ends, and it is only accurate for global variables at the end of the 
translation unit and only if they have internal linkage.  It is also basically 
meaningless within templates.

Please document that this is only meant to be a conservative approximation of 
whether the address is used;  it may be true in situations when the address is 
actually statically provable to not escape.  Alas, your patch does not 
implement a conservative approximation.  Among other things, you're only 
setting this bit in direct uses, but you really do need to be looking through 
anything that propagates reference-ness, including member accesses, 
base/derived casts, l-value reinterpreting casts, comma operators, and 
conditional operators;  I do not claim that this list is exhaustive.  Other 
things which take references to objects are lambda by-reference captures and 
member calls on the object;  this, too, I do not claim to be exhaustive.

That leads into the very interesting question of how we should validate the 
correctness of this bit.  We really can't rely on it until we have some sort of 
validation story.

Arguably, this bit should never be set on a variable of reference type.

+    /// \brief Whether this variable has its address taken or is referenced.
+    unsigned HasReference : 1;

+  /// Whether this variable has its address taken or is referenced.
+  bool hasReference() const { return VarDeclBits.HasReference; }
+  void setReference(bool ref) { VarDeclBits.HasReference = ref; }

This is a poor choice of names;  it is confusable with both the concept of a 
variable of reference type and the concept of whether a declaration has been 
referenced in the translation unit.  I would go with isAddressTaken / 
setAddressTaken, with the C++ behavior with references being understood (and 
documented).

Also, the semantics you're actually tracking are quite a bit more subtle than 
whether the address it taken, because you're specifically ignoring 
initializations of const references.  That's quite suspect and quite a bit less 
generically useful.  Also note that it is not illegal to bind a const reference 
to something and then modify it through that reference, either due to a mutable 
field or due to the constness being cast away.

setAddressTaken can default its argument to true.

You are not initializing this field to false.

You are not serializing and deserialization this field.  The ParmVarDecl 
abbreviation should assume this bit is 'false', I guess.

--- lib/Sema/SemaInit.cpp       (revision 158223)
+++ lib/Sema/SemaInit.cpp       (working copy)
@@ -6211,6 +6211,12 @@
   Expr *InitE = Init.get();
   assert(InitE && "No initialization expression?");
 
+  QualType QT = Entity.getType();
+  if (QT->isReferenceType() && !QT.getNonReferenceType().isConstQualified())
+    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InitE->IgnoreParens()))
+      if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+        VD->setReference(true);

This is not an appropriate place for this check;  not everything goes through 
PerformCopyInitialization.  This needs to happen in 
InitializationSequence::Perform for a reference-binding step.

+  if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(op))
+    if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+      VD->setReference(true);

You're not even looking through dyn_casts here.  You should extract out a 
function which walks an expression and marks variables that are bound in this 
way.  Alternatively, you may be able to piggy-back on the C++11 ODR-use code.

John.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to