On Sep 11, 2012, at 10:16 PM, Rafael Espíndola <[email protected]>
wrote:
>> The logic of this routine is fairly broken. It's trying to find an object
>> construction (which is doesn't do correctly, even after your patch) and
>> using that to blacklist all of the ill-formed patterns, rather than
>> detecting based on the type and then white-listing the few exceptions.
>>
>> It should really check for the valid cases directly (scalar/vector types are
>> okay, class types are okay when we're using the trivial default ctor and the
>> dtor is trivial) and fail with a generic error if our type is not one of
>> those valid cases. That way, the restricted form of the checking for
>> CXXConstructExpr that's currently being used will suffice for detecting the
>> "constructed with trivial constructor" case.
>
> I think we still need to find object construction to decide if we need
> an OutDiag or not.
Ah, yes, that's correct. There's also a terrible case that your patch doesn't
get right, which is something like:
struct X { operator &int() const; }
const int &i = X();
The problem here, which I hadn't been thinking about before, is lifetime
extension for temporaries. We actually have to dig into the initializer
expression to find the CXXConstructExpr, even when the variable type is a
reference to a scalar type.
> The attached patch improves the existing logic by
> getting the CXXRecordDecl from the type, computing OutDiag early and
> having a white list for InDiag as you suggested.
+ // If the variable is not of record type (or array thereof) the
+ // initializer cannot be a trivial ctor and there is no destructor
+ // to worry about.
+ const Type *T = Init->getType().getTypePtr();
+ if (T->isArrayType())
+ T = T->getBaseElementTypeUnsafe();
+ const CXXRecordDecl *Record = T->getAsCXXRecordDecl();
+ if (!Record)
+ return ScopePair(diag::note_protected_by_variable_init, 0);
+
This early exit seems not to work, per my example above.
+ // If we need to call a non trivial destructor for this variable,
+ // record an out diagnostic.
+ unsigned OutDiag = 0;
+ if (!Record->hasTrivialDestructor() && !isa<DeclRefExpr>(Init))
+ OutDiag = diag::note_exits_dtor;
I don't see what the DeclRefExpr check is meant to do.
FWIW, here's my test from above in a form that you can add to your patch:
namespace test13 {
struct C {
C(int x);
~C();
operator int&() const;
};
void f(void **ip) {
static void *ips[] = { &&l0 };
l0: // expected-note {{possible target of indirect goto}}
const int &c1 = C(1); // expected-note {{jump exits scope of variable with
non-trivial destructor}}
goto *ip; // expected-error {{indirect goto might cross protected scopes}}
}
}
- Doug
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits