From: Leonard Chan Date: Mon, 7 Dec 2020 22:39:42 +0000 (-0800) Subject: [clang] Fix noderef for array member of deref expr X-Git-Tag: llvmorg-13-init~4124 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=155fca3cae275562e626d3e4fbfac70b4b75d2e7;p=platform%2Fupstream%2Fllvm.git [clang] Fix noderef for array member of deref expr Committing on behalf of thejh (Jann Horn). Given an attribute((noderef)) pointer "p" to the struct struct s { int a[2]; }; ensure that the following expressions are treated the same way by the noderef logic: p->a (*p).a Until now, the first expression would be treated correctly (nothing is added to PossibleDerefs because CheckMemberAccessOfNoDeref() bails out on array members), but the second expression would incorrectly warn because "*p" creates a PossibleDerefs entry. Handle this case the same way as for the AddrOf operator. Differential Revision: https://reviews.llvm.org/D92140 --- diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 23cfae8..3e9d2a0 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1739,12 +1739,23 @@ void Sema::CheckMemberAccessOfNoDeref(const MemberExpr *E) { 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 index 3388f2a..b548ffa 100644 --- a/clang/test/Frontend/noderef.c +++ b/clang/test/Frontend/noderef.c @@ -73,6 +73,7 @@ int test() { // 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}}