================
Comment at: include/clang/Sema/Sema.h:395-396
@@ -392,1 +394,4 @@
 
+  /// \brief All delete-expressions within the translation unit.
+  llvm::SmallPtrSet<const CXXDeleteExpr *, 4> DeleteExprs;
+
----------------
ismailp wrote:
> rsmith wrote:
> > This is not a reasonable way to track the relevant state here.
> > 
> > The interesting cases are `VarDecl`s and `FieldDecl`s. For `VarDecl`s, at 
> > the point where we see the `delete`, you can immediately check whether you 
> > have an new-expression as an initializer (and don't worry about the obscure 
> > cases where an initializer comes after the use). For `FieldDecl`s, perform 
> > the check where you see the `delete`, and if you see either (a) no 
> > constructor with a matching `new`, or (b) only constructors with the wrong 
> > kind of `new`, then add your `delete` to a list to check at the end of the 
> > TU.
> > 
> > That way, in almost all cases we can deal with the diagnostic immediately 
> > rather than at end of TU. (This avoids building up a big set of all delete 
> > expressions.)
> > 
> > You'll also need to figure out how you're going to handle 
> > serialization/deserialization here, in the case where you hit one of these 
> > "not sure" cases in a PCH or similar. To that end, you should probably 
> > store a list of `{SourceLocation, FieldDecl}` pairs, or -- better -- a map 
> > from `FieldDecl` to the first source location where we saw a `delete`. 
> > (You'll need one extra bit to describe whether it was `delete` or 
> > `delete[]` I suppose...).
> I have implemented the first half of the patch, slightly different than your 
> suggestion. We diagnose this immediately for `VarDecl`, as you said. For 
> `FieldDecl`s, delete expression is queued, if at least one constructor isn't 
> defined (yet). Otherwise (if all constructor definitions are visible), 
> warning is issued in `ActOnCXXDelete` right before function returns. Could 
> you please explain the rationale for your point (b)? If we can see all 
> constructors while analyzing a `CXXDeleteExpr`, we can reason about 
> constructors and in-class initializers immediately. If no constructor 
> initializes the member, we check in-class initializer (if exists). If all 
> constructors initialize member with mismatching type of `new`, then we can 
> diagnose them all immediately, instead of postponing it to the end of 
> translation unit. I can think of only one case (aside from PCH case) that 
> requires postponing this analysis to the end of translation unit; that is, 
> when we cannot see at least one const!
 ructor's definition.
> 
> I have a few questions regarding PCH/external source. I have no prior 
> experience with ASTReader/Writer at all. Sorry, if my questions don't make 
> any sense. Do you mean we should handle following case:
>   // header; compiled as pch.
>   #ifndef header
>   struct X {
>     int *a;
>     ~X() { delete a; }  // not sure
>     X();
>    };
>    #endif
> 
>   // source file, includes above pch
>   #include "header"
>   X::X() : a(new int[1]) { }
> 
> We encounter with a delete-expr in a PCH. We can't prove anything, because we 
> can't see definition of `X::X()` yet. Even if there was an in-class 
> initializer, that wouldn't help, exactly for the same reason. `X::X()` will 
> be visible only at the end of translation unit. Therefore, we must write this 
> information somewhere in PCH so that we can load it at the end of translation 
> unit.
> 
> I have followed `UndefinedButUsed` as a serialization/deserialization 
> example. As far as I understood, I need to write a record, and read it back. 
> I blindly followed your suggestion here :) This record contains, as you said, 
> `FieldDecl`, `SourceLocation` and a bit indicating array form. I put them in 
> an `std::tuple<FieldDecl *, SourceLocation, bool>`. Can that "bit" be 
> represented as `APInt(width=1)`? I did, roughly:
>   RecordData DeleteExprsToAnalyze;
>   AddDeclRef(get<0>(tuple), DeleteExprsToAnalyze);
>   AddSource(get<1>(tuple), DeleteExprsToAnalyze);
>   AddAPInt(APInt(1, get<2>(tuple)), DeleteExprsToAnalyze);
>   // ...
>   if (!DeleteExprsToAnalyze.empty())
>     Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze);
> 
> I am trying the PCH part now. I would like to learn the right way, as I might 
> be doing something completely wrong.
> Could you please explain the rationale for your point (b)?

The idea is: if you haven't seen all the constructors yet, but you have seen a 
constructor that used the right kind of `new`, then there's no need to queue 
the expression; the `delete` is OK.

> If no constructor initializes the member, we check in-class initializer (if 
> exists).

This should probably be: if any constructor does not explicitly initialize the 
member, check the in-class initializer. (But it's probably redundant, since the 
constructor's initializer list will have been extended to contain a reference 
to  the in-class initializer in this case.)

> AddAPInt(APInt(1, get<2>(tuple)), DeleteExprsToAnalyze);

This is wasteful; `DeleteExprsToAnalyze` is a `SmallVector` of integers. Just 
do `DeleteExprsToAnalyze.push_back(get<2>(tuple));`. Other than that, this 
looks like the right approach.

http://reviews.llvm.org/D4661



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

Reply via email to