]> granicus.if.org Git - clang/commitdiff
Sema: Methods in unavailable classes are unavailable
authorDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 8 Mar 2016 10:28:52 +0000 (10:28 +0000)
committerDuncan P. N. Exon Smith <dexonsmith@apple.com>
Tue, 8 Mar 2016 10:28:52 +0000 (10:28 +0000)
Similar to the template cases in r262050, when a C++ method in an
unavailable struct/class calls unavailable API, don't diagnose an error.
I.e., this case was failing:

    void foo() __attribute__((unavailable));
    struct __attribute__((unavailable)) A {
      void bar() { foo(); }
    };

Since A is unavailable, A::bar is allowed to call foo.  However, we were
emitting a diagnostic here.  This commit checks up the context chain
from A::bar, in a manner inspired by SemaDeclAttr.cpp:isDeclUnavailable.

I expected to find other related issues but failed to trigger them:

- I wondered if DeclBase::getAvailability should check for
  `TemplateDecl` instead of `FunctionTemplateDecl`, but I couldn't find
  a way to trigger this.  I left behind a few extra tests to make sure
  we don't regress.

- I wondered if Sema::isFunctionConsideredUnavailable should be
  symmetric, checking up the context chain of the callee (this commit
  only checks up the context chain of the caller).  However, I couldn't
  think of a testcase that didn't require first referencing the
  unavailable type; this, we already diagnose.

rdar://problem/25030656

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@262921 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaOverload.cpp
test/SemaCXX/attr-unavailable.cpp

index 1765db6734e5a9fa6f923617e80ed9fc02a66ebd..a28ded474a75fd431d5bed5a8047a741675668e3 100644 (file)
@@ -1150,7 +1150,16 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
 /// \returns true if \arg FD is unavailable and current context is inside
 /// an available function, false otherwise.
 bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) {
-  return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
+  if (!FD->isUnavailable())
+    return false;
+
+  // Walk up the context of the caller.
+  Decl *C = cast<Decl>(CurContext);
+  do {
+    if (C->isUnavailable())
+      return false;
+  } while ((C = cast_or_null<Decl>(C->getDeclContext())));
+  return true;
 }
 
 /// \brief Tries a user-defined conversion from From to ToType.
index 430cb5cdb8c1cdd1219dc7fadb97bfaf50d8273d..bafae2ab43a2568bfcfec72d34222f4a6663a8fd 100644 (file)
@@ -116,3 +116,26 @@ void calls_unavail_templated() {
 void unavail_calls_unavail_templated() __attribute__((unavailable)) {
   unavail_templated(5);
 }
+
+void unavailable() __attribute((unavailable)); // \
+       expected-note 4{{candidate function has been explicitly made unavailable}}
+struct AvailableStruct {
+  void calls_unavailable() { unavailable(); } // \
+  expected-error{{call to unavailable function 'unavailable'}}
+  template <class U> void calls_unavailable() { unavailable(); } // \
+  expected-error{{call to unavailable function 'unavailable'}}
+};
+template <class T> struct AvailableStructTemplated {
+  void calls_unavailable() { unavailable(); } // \
+  expected-error{{call to unavailable function 'unavailable'}}
+  template <class U> void calls_unavailable() { unavailable(); } // \
+  expected-error{{call to unavailable function 'unavailable'}}
+};
+struct __attribute__((unavailable)) UnavailableStruct {
+  void calls_unavailable() { unavailable(); }
+  template <class U> void calls_unavailable() { unavailable(); }
+};
+template <class T> struct __attribute__((unavailable)) UnavailableStructTemplated {
+  void calls_unavailable() { unavailable(); }
+  template <class U> void calls_unavailable() { unavailable(); }
+};