Author: dexonsmith Date: Fri Feb 26 13:27:00 2016 New Revision: 262050 URL: http://llvm.org/viewvc/llvm-project?rev=262050&view=rev Log: 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 Modified: cfe/trunk/lib/AST/DeclBase.cpp cfe/trunk/lib/Lex/PPMacroExpansion.cpp cfe/trunk/test/SemaCXX/attr-unavailable.cpp Modified: cfe/trunk/lib/AST/DeclBase.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=262050&r1=262049&r2=262050&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp (original) +++ cfe/trunk/lib/AST/DeclBase.cpp Fri Feb 26 13:27:00 2016 @@ -467,6 +467,9 @@ static AvailabilityResult CheckAvailabil } 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; Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=262050&r1=262049&r2=262050&view=diff ============================================================================== --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original) +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Fri Feb 26 13:27:00 2016 @@ -1074,6 +1074,7 @@ static bool HasFeature(const Preprocesso .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) Modified: cfe/trunk/test/SemaCXX/attr-unavailable.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-unavailable.cpp?rev=262050&r1=262049&r2=262050&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/attr-unavailable.cpp (original) +++ cfe/trunk/test/SemaCXX/attr-unavailable.cpp Fri Feb 26 13:27:00 2016 @@ -5,7 +5,8 @@ double &foo(double); // expected-note {{ 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 AnotherUnav __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); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits