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 @@ -1739,12 +1739,23 @@ QualType ResultTy = E->getType(); - // Do not warn on member accesses to arrays since this returns an array - // lvalue and does not actually dereference memory. - if (isa(ResultTy)) - return; - - if (E->isArrow()) { + // Member accesses have four cases: + // 1: non-array member via "->": dereferences + // 2: non-array member via ".": nothing interesting happens + // 3: array member access via "->": nothing interesting happens + // (this returns an array lvalue and does not actually dereference memory) + // 4: array member access via ".": *adds* a layer of indirection + if (ResultTy->isArrayType()) { + if (!E->isArrow()) { + // This might be something like: + // (*structPtr).arrayMember + // which behaves roughly like: + // &(*structPtr).pointerMember + // in that the apparent dereference in the base expression does not + // actually happen. + CheckAddressOfNoDeref(E->getBase()); + } + } else if (E->isArrow()) { if (const auto *Ptr = dyn_cast( E->getBase()->getType().getDesugaredType(Context))) { if (Ptr->getPointeeType()->hasAttr(attr::NoDeref)) 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 @@ -73,6 +73,7 @@ // 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 + p = (*s2_noderef).a; // ok since result is an array in a struct p = s2_noderef->a2; // ok p = s2_noderef->b; // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}} p = s2_noderef->b2; // expected-warning{{dereferencing s2_noderef; was declared with a 'noderef' type}}