Skip to content

Commit

Permalink
Ignore noderef attribute in unevaluated context
Browse files Browse the repository at this point in the history
The noderef attribute is for catching code that accesses pointers in
a different address space. Unevaluated code is always safe in that regard.
  • Loading branch information
thejh authored and AaronBallman committed Nov 23, 2020
1 parent 1ec6086 commit 00dad9d
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 2 deletions.
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Expand Up @@ -4751,6 +4751,9 @@ void Sema::CheckAddressOfNoDeref(const Expr *E) {
}

void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) {
if (isUnevaluatedContext())
return;

QualType ResultTy = E->getType();
ExpressionEvaluationContextRecord &LastRecord = ExprEvalContexts.back();

Expand Down Expand Up @@ -14666,7 +14669,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
OpLoc, CanOverflow, CurFPFeatureOverrides());

if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) &&
!isa<ArrayType>(UO->getType().getDesugaredType(Context)))
!isa<ArrayType>(UO->getType().getDesugaredType(Context)) &&
!isUnevaluatedContext())
ExprEvalContexts.back().PossibleDerefs.insert(UO);

// Convert the result back to a half vector.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaExprMember.cpp
Expand Up @@ -1734,6 +1734,9 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
}

void Sema::CheckMemberAccessOfNoDeref(const MemberExpr *E) {
if (isUnevaluatedContext())
return;

QualType ResultTy = E->getType();

// Do not warn on member accesses to arrays since this returns an array
Expand Down
9 changes: 8 additions & 1 deletion clang/test/Frontend/noderef.c
Expand Up @@ -57,12 +57,19 @@ int test() {
p = &*(p + 1);

// Struct member access
struct S NODEREF *s; // expected-note 2 {{s declared here}}
struct S NODEREF *s; // expected-note 3 {{s declared here}}
x = s->a; // expected-warning{{dereferencing s; was declared with a 'noderef' type}}
x = (*s).b; // expected-warning{{dereferencing s; was declared with a 'noderef' type}}
p = &s->a;
p = &(*s).b;

// Most things in sizeof() can't actually access memory
x = sizeof(s->a); // ok
x = sizeof(*s); // ok
x = sizeof(s[0]); // ok
x = sizeof(s->a + (s->b)); // ok
x = sizeof(int[++s->a]); // expected-warning{{dereferencing s; was declared with a 'noderef' type}}

// 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
Expand Down
17 changes: 17 additions & 0 deletions clang/test/Frontend/noderef.cpp
Expand Up @@ -6,6 +6,11 @@

#define NODEREF __attribute__((noderef))

// Stub out types for 'typeid' to work.
namespace std {
class type_info {};
} // namespace std

void Normal() {
int NODEREF i; // expected-warning{{'noderef' can only be used on an array or pointer type}}
int NODEREF *i_ptr; // expected-note 2 {{i_ptr declared here}}
Expand Down Expand Up @@ -102,6 +107,18 @@ int ChildCall(NODEREF Child *child) { // expected-note{{child declared here}}
return child->func(); // expected-warning{{dereferencing child; was declared with a 'noderef' type}}
}

std::type_info TypeIdPolymorphic(NODEREF A *a) { // expected-note{{a declared here}}
return typeid(*a); // expected-warning{{dereferencing a; was declared with a 'noderef' type}}
}

class SimpleClass {
int a;
};

std::type_info TypeIdNonPolymorphic(NODEREF SimpleClass *simple) {
return typeid(*simple);
}

template <class Ty>
class B {
Ty NODEREF *member;
Expand Down

0 comments on commit 00dad9d

Please sign in to comment.