forked from OSchip/llvm-project
SemaCXX: Support templates in availability attributes
If the availability context is `FunctionTemplateDecl`, we should look through it to the `FunctionDecl`. This prevents a diagnostic in the following case: class C __attribute__((unavailable)); template <class T> void foo(C&) __attribute__((unavailable)); This adds tests for availability in templates in many other cases, but that was the only case that failed before this patch. I added a feature `__has_feature(attribute_availability_in_templates)` so users can test for this. rdar://problem/24561029 llvm-svn: 262050
This commit is contained in:
parent
2993854bb4
commit
ec599a906b
|
@ -467,6 +467,9 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
|
|||
}
|
||||
|
||||
AvailabilityResult Decl::getAvailability(std::string *Message) const {
|
||||
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(this))
|
||||
return FTD->getTemplatedDecl()->getAvailability(Message);
|
||||
|
||||
AvailabilityResult Result = AR_Available;
|
||||
std::string ResultMessage;
|
||||
|
||||
|
|
|
@ -1074,6 +1074,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
|
|||
.Case("attribute_availability_tvos", true)
|
||||
.Case("attribute_availability_watchos", true)
|
||||
.Case("attribute_availability_with_strict", true)
|
||||
.Case("attribute_availability_in_templates", true)
|
||||
.Case("attribute_cf_returns_not_retained", true)
|
||||
.Case("attribute_cf_returns_retained", true)
|
||||
.Case("attribute_cf_returns_on_parameters", true)
|
||||
|
|
|
@ -5,7 +5,8 @@ double &foo(double); // expected-note {{candidate}}
|
|||
void foo(...) __attribute__((__unavailable__)); // expected-note {{candidate function}} \
|
||||
// expected-note{{'foo' has been explicitly marked unavailable here}}
|
||||
|
||||
void bar(...) __attribute__((__unavailable__)); // expected-note 2{{explicitly marked unavailable}}
|
||||
void bar(...) __attribute__((__unavailable__)); // expected-note 2{{explicitly marked unavailable}} \
|
||||
// expected-note 2{{candidate function has been explicitly made unavailable}}
|
||||
|
||||
void test_foo(short* sp) {
|
||||
int &ir = foo(1);
|
||||
|
@ -56,3 +57,62 @@ typedef enum UnavailableEnum AnotherUnavailableEnum; // expected-error {{'Unavai
|
|||
|
||||
__attribute__((unavailable))
|
||||
UnavailableEnum testUnavailable(UnavailableEnum X) { return X; }
|
||||
|
||||
|
||||
// Check that unavailable classes can be used as arguments to unavailable
|
||||
// function, particularly in template functions.
|
||||
#if !__has_feature(attribute_availability_in_templates)
|
||||
#error "Missing __has_feature"
|
||||
#endif
|
||||
class __attribute((unavailable)) UnavailableClass; // \
|
||||
expected-note 3{{'UnavailableClass' has been explicitly marked unavailable here}}
|
||||
void unavail_class(UnavailableClass&); // expected-error {{'UnavailableClass' is unavailable}}
|
||||
void unavail_class_marked(UnavailableClass&) __attribute__((unavailable));
|
||||
template <class T> void unavail_class(UnavailableClass&); // expected-error {{'UnavailableClass' is unavailable}}
|
||||
template <class T> void unavail_class_marked(UnavailableClass&) __attribute__((unavailable));
|
||||
template <class T> void templated(T&);
|
||||
void untemplated(UnavailableClass &UC) { // expected-error {{'UnavailableClass' is unavailable}}
|
||||
templated(UC);
|
||||
}
|
||||
void untemplated_marked(UnavailableClass &UC) __attribute__((unavailable)) {
|
||||
templated(UC);
|
||||
}
|
||||
|
||||
template <class T> void templated_calls_bar() { bar(); } // \
|
||||
// expected-error{{call to unavailable function 'bar'}}
|
||||
template <class T> void templated_calls_bar_arg(T v) { bar(v); } // \
|
||||
// expected-error{{call to unavailable function 'bar'}}
|
||||
template <class T> void templated_calls_bar_arg_never_called(T v) { bar(v); }
|
||||
|
||||
template <class T>
|
||||
void unavail_templated_calls_bar() __attribute__((unavailable)) { // \
|
||||
expected-note{{candidate function [with T = int] has been explicitly made unavailable}}
|
||||
bar(5);
|
||||
}
|
||||
template <class T>
|
||||
void unavail_templated_calls_bar_arg(T v) __attribute__((unavailable)) { // \
|
||||
expected-note{{candidate function [with T = int] has been explicitly made unavailable}}
|
||||
bar(v);
|
||||
}
|
||||
|
||||
void calls_templates_which_call_bar() {
|
||||
templated_calls_bar<int>();
|
||||
|
||||
templated_calls_bar_arg(5); // \
|
||||
expected-note{{in instantiation of function template specialization 'templated_calls_bar_arg<int>' requested here}}
|
||||
|
||||
unavail_templated_calls_bar<int>(); // \
|
||||
expected-error{{call to unavailable function 'unavail_templated_calls_bar'}}
|
||||
|
||||
unavail_templated_calls_bar_arg(5); // \
|
||||
expected-error{{call to unavailable function 'unavail_templated_calls_bar_arg'}}
|
||||
}
|
||||
|
||||
template <class T> void unavail_templated(T) __attribute__((unavailable)); // \
|
||||
expected-note{{candidate function [with T = int] has been explicitly made unavailable}}
|
||||
void calls_unavail_templated() {
|
||||
unavail_templated(5); // expected-error{{call to unavailable function 'unavail_templated'}}
|
||||
}
|
||||
void unavail_calls_unavail_templated() __attribute__((unavailable)) {
|
||||
unavail_templated(5);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue