diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1810,6 +1810,14 @@ Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) MemberType = Context.getQualifiedType(MemberType, Combined); + + // Pick up NoDeref from the base in case we end up using AddrOf on the + // result. E.g. the expression + // &someNoDerefPtr->pointerMember + // should be a noderef pointer again. + if (BaseType->hasAttr(attr::NoDeref)) + MemberType = + Context.getAttributedType(attr::NoDeref, MemberType, MemberType); } auto *CurMethod = dyn_cast(CurContext); diff --git a/clang/test/Frontend/noderef.c b/clang/test/Frontend/noderef.c --- a/clang/test/Frontend/noderef.c +++ b/clang/test/Frontend/noderef.c @@ -70,6 +70,12 @@ x = sizeof(s->a + (s->b)); // ok x = sizeof(int[++s->a]); // expected-warning{{dereferencing s; was declared with a 'noderef' type}} + // Struct member access should carry NoDeref type information through to an + // enclosing AddrOf. + p2 = &s->a; // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}} + p2 = &(*s).a; // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}} + x = *&s->a; // expected-warning{{dereferencing expression marked as 'noderef'}} + // Nested struct access struct S2 NODEREF *s2_noderef; // expected-note 5 {{s2_noderef declared here}} p = s2_noderef->a; // ok since result is an array in a struct @@ -113,7 +119,7 @@ p = s2_arr[1]->a; p = s2_arr[1]->b; // expected-warning{{dereferencing expression marked as 'noderef'}} - int **bptr = &s2_arr[1]->b; + int *NODEREF *bptr = &s2_arr[1]->b; x = s2->s2->a; // expected-warning{{dereferencing expression marked as 'noderef'}} x = s2_noderef->a[1]; // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}}