rsmith added inline comments.

================
Comment at: lib/Parse/ParseExpr.cpp:1126
+
+    Actions.StartCheckingNoDeref();
+
----------------
leonardchan wrote:
> rsmith wrote:
> > This parser-driven start/stop mechanism will not work in C++ templates. 
> > Instead, can you remove the "start" part and check the noderef exprs as 
> > part of popping the ExprEvaluationContextRecord?
> I'm not sure if I should remove the the start and stop methods because for a 
> regular C program, the Push/PopExprEvaluationContextRecord functions don't 
> seem to be called, and even when they are called in C++, the initial record 
> that exists on the stack isn't popped at all.
> 
> Since pending noderef expressions are still parsed and added to the last 
> record during template instantiation, doing another check when popping covers 
> all noderef exprs added during instantiation.
`PushExpressionEvaluationContext` / `PopExpressionEvaluationContext` are called 
regardless of which language we're parsing. If we're missing 
`ExpressionEvaluationContext` records around some expression parsing, we should 
fix that. We should never be creating expressions within the initial 
`ExpressionEvaluationContext` record (except perhaps during error recovery).

> Since pending noderef expressions are still parsed and added to the last 
> record during template instantiation, doing another check when popping covers 
> all noderef exprs added during instantiation.

That's not how template instantiation works in Clang. We don't re-parse, we 
perform a recursive tree transformation that does not involve the parser.


================
Comment at: lib/Sema/SemaExpr.cpp:14230-14242
+class DeclRefFinder : public ConstEvaluatedExprVisitor<DeclRefFinder> {
+public:
+  typedef ConstEvaluatedExprVisitor<DeclRefFinder> Inherited;
+
+  DeclRefFinder(ASTContext &Ctx) : Inherited(Ctx) {}
+
+  void VisitDeclRefExpr(const DeclRefExpr *E) { DeclRef = E; }
----------------
leonardchan wrote:
> rsmith wrote:
> > rsmith wrote:
> > > I don't see any reason to assume that the `DeclRefExpr` found by this 
> > > visitor will be the one you're interested in (the one the `noderef` 
> > > attribute came from).
> > > 
> > > How about instead you walk over only expressions that you *know* preserve 
> > > `noderef`, and if you can't find a declaration as the source of the 
> > > `noderef` attribute, produce a differently-worded diagnostic that doesn't 
> > > give a variable name?
> > This comment is marked done but has not been addressed.
> My bad. My response to this was adding a check in 
> `StopCheckingNoDerefAndWarn` where we check if the `DeclRefExpr` is `nullptr` 
> and throw the appropriate error if it is found or not.
> 
> Although I can't come up with an example where this doesn't get the declref 
> we want, since the expressions we pass to this visitor are all our marked 
> noderef expressions (which we check via the attribute on the type). So even 
> if we have a complex expression that has multiple declrefs, all noderef 
> declrefs should be checked by this.
How about this:

```
int __attribute__((noderef)) *a;
int __attribute__((noderef)) *b;
int __attribute__((noderef)) *c;
*(a = b, c);
```

The first noderef pointer the visitor finds will be `a`, but that's not the one 
that was dereferenced.


================
Comment at: lib/Sema/SemaExpr.cpp:14251-14253
+    if (const auto *Ptr = dyn_cast<PointerType>(Ty))
+      Inner = Ptr->getPointeeType();
+    else if (const auto *Arr = dyn_cast<ArrayType>(Ty))
----------------
aaron.ballman wrote:
> I don't think this strips off sugar from the type, so I suspect it won't 
> properly handle a typedef to a pointer type, for instance, or a type 
> including parens. You should add tests for these cases.
Calling `getDesugaredType` is not the right way to address this: use 
`Ty->getAs<PointerType>()` and `Context.getAsArrayType(Ty)` instead.


================
Comment at: lib/Sema/SemaExpr.cpp:4164-4177
+bool Sema::TypeHasNoDeref(QualType Ty) {
+  // Strip off everything but attributes.
+  QualType OldTy;
+  while (Ty != OldTy && !isa<AttributedType>(Ty)) {
+    OldTy = Ty;
+    Ty = Ty.getSingleStepDesugaredType(Context);
+  }
----------------
You can just use `Ty->hasAttr(attr::NoDeref)` for this now.


================
Comment at: lib/Sema/SemaExpr.cpp:4263-4266
+  auto FoundExpr = LastRecord.PossibleDerefs.find(StrippedExpr);
+  if (FoundExpr != LastRecord.PossibleDerefs.end()) {
+    LastRecord.PossibleDerefs.erase(*FoundExpr);
+  }
----------------
Do you need to do this both here and after walking into the `.` expressions? It 
seems to me that it would be sufficient to first walk into the LHS of any `.` 
expressions, and then remove the result from `PossibleDerefs`.


================
Comment at: lib/Sema/SemaExpr.cpp:4269
+  const Expr *Base = nullptr;
+  while (const auto *Member = dyn_cast<MemberExpr>(StrippedExpr)) {
+    Base = Member->getBase()->IgnoreParenImpCasts();
----------------
You should check the `MemberExpr` is a `.` rather than a `->` before stepping 
into it.


================
Comment at: lib/Sema/SemaExpr.cpp:4278
+    auto FoundBase = LastRecord.PossibleDerefs.find(Base);
+    if (TypeHasNoDeref(BaseTy) &&
+        FoundBase != LastRecord.PossibleDerefs.end()) {
----------------
This type check seems incorrect, because you don't propagate the type through 
`->` operators. In particular, given

   `&noderef_ptr->x.y`

you will step back to `noderef_ptr->x`, which will not have a noderef type, and 
not remove it from the set as a result. It seems best to drop this type check.


================
Comment at: lib/Sema/SemaExpr.cpp:4289
+
+  if (TypeHasNoDeref(ResultTy)) {
+    LastRecord.PossibleDerefs.insert(E);
----------------
Do you ensure that the `noderef` attribute will be on the innermost level of 
the array type? I think you'll need to do so in order to warn on:

```
typedef int A[32];
typedef A __attribute__((noderef)) *B;
int f(B b) { return (*B)[1]; }
```

(Here, we have a pointer to a noderef annotated array of non-noderef-annotated 
int. So I think we will not emit a warning from the first dereference, because 
we have a pointer to an array, and we will not emit a warning from the second 
dereference in the array indexing, because the result type does not have the 
noderef attribute.)


================
Comment at: lib/Sema/SemaExpr.cpp:4297
+  const Expr *Base = E->getBase();
+  const QualType &BaseTy = Base->getType();
+  if (!(isa<ArrayType>(BaseTy) || isa<PointerType>(BaseTy)))
----------------
`QualType`s should be held by value, not by reference.


================
Comment at: lib/Sema/SemaExpr.cpp:4302-4308
+  if (const auto *Member = dyn_cast<MemberExpr>(Base->IgnoreParenCasts())) {
+    const QualType &MemberBaseTy = Member->getBase()->getType();
+    if (const auto *Ptr = dyn_cast<PointerType>(MemberBaseTy)) {
+      if (TypeHasNoDeref(Ptr->getPointeeType()))
+        LastRecord.PossibleDerefs.insert(E);
+    }
+  }
----------------
There could be a sequence of `MemberExpr`s here, and watch out for `.` vs `->`.


================
Comment at: lib/Sema/SemaExpr.cpp:12865-12866
+
+  if (Opc == UO_Deref && TypeHasNoDeref(UO->getType()))
+    ExprEvalContexts.back().PossibleDerefs.insert(UO);
+
----------------
You should probably not add the expression to the list if it's of array type. 
Given:

```
typedef int A[32];
typedef A __attribute__((noderef)) *B;
B b;
int __attribute__((noderef)) *p = *b;
```

... you should not warn on the "dereference" here. That should either be 
handled here or by treating an array-to-pointer decay operation the same as an 
"address of" operation and removing pending derefs from the list.


Repository:
  rC Clang

https://reviews.llvm.org/D49511



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to