From 01cd9f07cba0ba13c209f81058e753a0935b4af6 Mon Sep 17 00:00:00 2001
From: "Duncan P. N. Exon Smith" <dexonsmith@apple.com>
Date: Mon, 8 Feb 2016 18:35:24 -0800
Subject: [PATCH] SemaCXX: Support templates in availability attributes

Add support for templates in availability attributes.
- If the context for an availability diagnostic is a
  `FunctionTemplateDecl`, look through it to the `FunctionDecl`.
- Add `__has_feature(attribute_availability_in_templates)`.
---
 lib/AST/DeclBase.cpp              |  3 +++
 lib/Lex/PPMacroExpansion.cpp      |  1 +
 test/SemaCXX/attr-unavailable.cpp | 22 ++++++++++++++++++++++
 3 files changed, 26 insertions(+)

diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index b699bec..e498c7a 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -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;
 
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 11b4a0b..395f859 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -1067,6 +1067,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
       .Case("attribute_availability_with_version_underscores", true)
       .Case("attribute_availability_tvos", true)
       .Case("attribute_availability_watchos", 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)
diff --git a/test/SemaCXX/attr-unavailable.cpp b/test/SemaCXX/attr-unavailable.cpp
index 51dc8fe..e1489b9 100644
--- a/test/SemaCXX/attr-unavailable.cpp
+++ b/test/SemaCXX/attr-unavailable.cpp
@@ -56,3 +56,25 @@ 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 {{'UnavailableClass' has been explicitly marked unavailable here}} \
+        expected-note {{'UnavailableClass' has been explicitly marked unavailable here}} \
+        expected-note {{'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);
+}
-- 
2.6.4 (Apple Git-63)

