forked from OSchip/llvm-project
Sema: Methods in unavailable classes are unavailable
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 llvm-svn: 262921
This commit is contained in:
parent
1ab4adb1d3
commit
8536392a83
|
@ -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.
|
||||
|
|
|
@ -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(); }
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue