Ignore noderef attribute in unevaluated context
authorJann Horn <jannh@google.com>
Mon, 23 Nov 2020 13:10:35 +0000 (08:10 -0500)
committerAaron Ballman <aaron@aaronballman.com>
Mon, 23 Nov 2020 13:10:35 +0000 (08:10 -0500)
The noderef attribute is for catching code that accesses pointers in
a different address space. Unevaluated code is always safe in that regard.

clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaExprMember.cpp
clang/test/Frontend/noderef.c
clang/test/Frontend/noderef.cpp

index 60a685bfdf158f74bb4751ff34696c5632c2db5a..5580cdf136914af2ff292686f23c4ba86eff14bf 100644 (file)
@@ -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();
 
@@ -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.
index 93ed756e084bbdb94959fcf3bff1b72107b9263f..23cfae81df461f259169d83b5f5099bc7db81218 100644 (file)
@@ -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
index b072b995fcf645a02f047446c2274bd03db90019..3388f2a399924c85ee688fd1ce5bb61f135600c3 100644 (file)
@@ -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
index 32d5ca34d1b1ba52fded97b79c720cd56c429623..68342a8e6467b8b3b2a71b38f4b5edfbf01a070f 100644 (file)
@@ -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}}
@@ -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;