[clang] [Clang] Move the builtin workaround logic to the lexer (PR #96097)

Vlad Serebrennikov via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 29 08:49:36 PDT 2024


https://github.com/Endilll updated https://github.com/llvm/llvm-project/pull/96097

>From b77b2d9b10ad90ee67893904732003bf11eec21d Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 19 Jun 2024 19:47:43 +0200
Subject: [PATCH 1/5] [Clang] Move the builtin workaround logic to the lexer

---
 .../include/clang/Basic/DiagnosticLexKinds.td |  4 +
 clang/include/clang/Basic/IdentifierTable.h   | 19 +++-
 clang/include/clang/Parse/Parser.h            |  4 -
 clang/lib/Basic/IdentifierTable.cpp           | 75 +++++++++++++++
 clang/lib/Lex/Preprocessor.cpp                |  5 +
 clang/lib/Parse/ParseDecl.cpp                 | 19 +---
 clang/lib/Parse/ParseDeclCXX.cpp              | 71 ---------------
 clang/lib/Parse/ParseExpr.cpp                 | 91 -------------------
 clang/test/SemaCXX/libstdcxx_is_pod_hack.cpp  | 14 +--
 9 files changed, 109 insertions(+), 193 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 25fbfe83fa2bc..372d549dc59ba 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -85,6 +85,10 @@ def warn_c99_keyword : Warning<"'%0' is a keyword in C99">,
 def warn_c23_keyword : Warning<"'%0' is a keyword in C23">,
   InGroup<C23Compat>, DefaultIgnore;
 
+def warn_deprecated_builtin_replacement : Warning<
+  "using the name of the builtin '%0' outside of "
+  "a builtin invocation is deprecated">, InGroup<KeywordCompat>;
+
 def ext_unterminated_char_or_string : ExtWarn<
   "missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>;
 def ext_empty_character : ExtWarn<"empty character constant">,
diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index ae9ebd9f59154..00d1f9b7c9949 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -196,6 +196,9 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
   LLVM_PREFERRED_TYPE(bool)
   unsigned IsFinal : 1;
 
+  LLVM_PREFERRED_TYPE(bool)
+  unsigned IsReusableBuiltinName : 1;
+
   // 22 bits left in a 64-bit word.
 
   // Managed by the language front-end.
@@ -213,7 +216,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
         IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false),
         RevertedTokenID(false), OutOfDate(false), IsModulesImport(false),
         IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false),
-        IsRestrictExpansion(false), IsFinal(false) {}
+        IsRestrictExpansion(false), IsFinal(false),
+        IsReusableBuiltinName(false) {}
 
 public:
   IdentifierInfo(const IdentifierInfo &) = delete;
@@ -332,6 +336,16 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
     RevertedTokenID = false;
   }
 
+  bool isReusableBuiltinName() const { return IsReusableBuiltinName; };
+
+  void setIsReusableBuiltinName(bool Val) {
+    IsReusableBuiltinName = Val;
+    if (Val)
+      NeedsHandleIdentifier = true;
+    else
+      RecomputeNeedsHandleIdentifier();
+  };
+
   /// Return the preprocessor keyword ID for this identifier.
   ///
   /// For example, "define" will return tok::pp_define.
@@ -569,7 +583,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
   void RecomputeNeedsHandleIdentifier() {
     NeedsHandleIdentifier = isPoisoned() || hasMacroDefinition() ||
                             isExtensionToken() || isFutureCompatKeyword() ||
-                            isOutOfDate() || isModulesImport();
+                            isReusableBuiltinName() || isOutOfDate() ||
+                            isModulesImport();
   }
 };
 
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index d054b8cf0d240..ed5d32bf5e076 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -169,10 +169,6 @@ class Parser : public CodeCompletionHandler {
   mutable IdentifierInfo *Ident_import;
   mutable IdentifierInfo *Ident_module;
 
-  // C++ type trait keywords that can be reverted to identifiers and still be
-  // used as type traits.
-  llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
-
   std::unique_ptr<PragmaHandler> AlignHandler;
   std::unique_ptr<PragmaHandler> GCCVisibilityHandler;
   std::unique_ptr<PragmaHandler> OptionsHandler;
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index feea84544d62f..f2f2fb822a378 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -246,6 +246,79 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
   return CurStatus;
 }
 
+static bool isReusableBuiltinName(tok::TokenKind TokenCode) {
+#define RTT_JOIN(X, Y) X##Y
+#define REVERTIBLE_TYPE_TRAIT(Name)                                            \
+  case RTT_JOIN(tok::kw_, Name):                                               \
+    return true;
+
+  switch (TokenCode) {
+  default:
+    return false;
+    REVERTIBLE_TYPE_TRAIT(__is_abstract);
+    REVERTIBLE_TYPE_TRAIT(__is_aggregate);
+    REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
+    REVERTIBLE_TYPE_TRAIT(__is_array);
+    REVERTIBLE_TYPE_TRAIT(__is_assignable);
+    REVERTIBLE_TYPE_TRAIT(__is_base_of);
+    REVERTIBLE_TYPE_TRAIT(__is_bounded_array);
+    REVERTIBLE_TYPE_TRAIT(__is_class);
+    REVERTIBLE_TYPE_TRAIT(__is_complete_type);
+    REVERTIBLE_TYPE_TRAIT(__is_compound);
+    REVERTIBLE_TYPE_TRAIT(__is_const);
+    REVERTIBLE_TYPE_TRAIT(__is_constructible);
+    REVERTIBLE_TYPE_TRAIT(__is_convertible);
+    REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
+    REVERTIBLE_TYPE_TRAIT(__is_destructible);
+    REVERTIBLE_TYPE_TRAIT(__is_empty);
+    REVERTIBLE_TYPE_TRAIT(__is_enum);
+    REVERTIBLE_TYPE_TRAIT(__is_floating_point);
+    REVERTIBLE_TYPE_TRAIT(__is_final);
+    REVERTIBLE_TYPE_TRAIT(__is_function);
+    REVERTIBLE_TYPE_TRAIT(__is_fundamental);
+    REVERTIBLE_TYPE_TRAIT(__is_integral);
+    REVERTIBLE_TYPE_TRAIT(__is_interface_class);
+    REVERTIBLE_TYPE_TRAIT(__is_layout_compatible);
+    REVERTIBLE_TYPE_TRAIT(__is_literal);
+    REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
+    REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
+    REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
+    REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
+    REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
+    REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
+    REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
+    REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
+    REVERTIBLE_TYPE_TRAIT(__is_nothrow_convertible);
+    REVERTIBLE_TYPE_TRAIT(__is_nullptr);
+    REVERTIBLE_TYPE_TRAIT(__is_object);
+    REVERTIBLE_TYPE_TRAIT(__is_pod);
+    REVERTIBLE_TYPE_TRAIT(__is_pointer);
+    REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
+    REVERTIBLE_TYPE_TRAIT(__is_reference);
+    REVERTIBLE_TYPE_TRAIT(__is_referenceable);
+    REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
+    REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
+    REVERTIBLE_TYPE_TRAIT(__is_same);
+    REVERTIBLE_TYPE_TRAIT(__is_scalar);
+    REVERTIBLE_TYPE_TRAIT(__is_scoped_enum);
+    REVERTIBLE_TYPE_TRAIT(__is_sealed);
+    REVERTIBLE_TYPE_TRAIT(__is_signed);
+    REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
+    REVERTIBLE_TYPE_TRAIT(__is_trivial);
+    REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
+    REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
+    REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
+    REVERTIBLE_TYPE_TRAIT(__is_trivially_equality_comparable);
+    REVERTIBLE_TYPE_TRAIT(__is_unbounded_array);
+    REVERTIBLE_TYPE_TRAIT(__is_union);
+    REVERTIBLE_TYPE_TRAIT(__is_unsigned);
+    REVERTIBLE_TYPE_TRAIT(__is_void);
+    REVERTIBLE_TYPE_TRAIT(__is_volatile);
+    REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary);
+  }
+  return false;
+}
+
 /// AddKeyword - This method is used to associate a token ID with specific
 /// identifiers because they are language keywords.  This causes the lexer to
 /// automatically map matching identifiers to specialized token codes.
@@ -261,6 +334,8 @@ static void AddKeyword(StringRef Keyword,
       Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
   Info.setIsExtensionToken(AddResult == KS_Extension);
   Info.setIsFutureCompatKeyword(AddResult == KS_Future);
+  Info.setIsReusableBuiltinName(LangOpts.CPlusPlus &&
+                                isReusableBuiltinName(TokenCode));
 }
 
 /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 44b69a58f3411..7fb1e4db3b87e 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -837,6 +837,11 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
     II.setIsFutureCompatKeyword(false);
   }
 
+  if (II.isReusableBuiltinName() && !isNextPPTokenLParen()) {
+    Identifier.setKind(tok::identifier);
+    Diag(Identifier, diag::warn_deprecated_builtin_replacement) << II.getName();
+  }
+
   // If this is an extension token, diagnose its use.
   // We avoid diagnosing tokens that originate from macro definitions.
   // FIXME: This warning is disabled in cases where it shouldn't be,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index c528917437332..c1dea20e298f0 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3906,24 +3906,7 @@ void Parser::ParseDeclarationSpecifiers(
 
       continue;
     }
-
-    case tok::kw___is_signed:
-      // GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang
-      // typically treats it as a trait. If we see __is_signed as it appears
-      // in libstdc++, e.g.,
-      //
-      //   static const bool __is_signed;
-      //
-      // then treat __is_signed as an identifier rather than as a keyword.
-      if (DS.getTypeSpecType() == TST_bool &&
-          DS.getTypeQualifiers() == DeclSpec::TQ_const &&
-          DS.getStorageClassSpec() == DeclSpec::SCS_static)
-        TryKeywordIdentFallback(true);
-
-      // We're done with the declaration-specifiers.
-      goto DoneWithDeclSpec;
-
-      // typedef-name
+    // typedef-name
     case tok::kw___super:
     case tok::kw_decltype:
     case tok::identifier:
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d02548f6441f9..e863f24770b10 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1718,77 +1718,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
   // C++11 attributes
   SourceLocation AttrFixitLoc = Tok.getLocation();
 
-  if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) &&
-      !Tok.isAnnotation() && Tok.getIdentifierInfo() &&
-      Tok.isOneOf(
-#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
-#include "clang/Basic/TransformTypeTraits.def"
-          tok::kw___is_abstract,
-          tok::kw___is_aggregate,
-          tok::kw___is_arithmetic,
-          tok::kw___is_array,
-          tok::kw___is_assignable,
-          tok::kw___is_base_of,
-          tok::kw___is_bounded_array,
-          tok::kw___is_class,
-          tok::kw___is_complete_type,
-          tok::kw___is_compound,
-          tok::kw___is_const,
-          tok::kw___is_constructible,
-          tok::kw___is_convertible,
-          tok::kw___is_convertible_to,
-          tok::kw___is_destructible,
-          tok::kw___is_empty,
-          tok::kw___is_enum,
-          tok::kw___is_floating_point,
-          tok::kw___is_final,
-          tok::kw___is_function,
-          tok::kw___is_fundamental,
-          tok::kw___is_integral,
-          tok::kw___is_interface_class,
-          tok::kw___is_literal,
-          tok::kw___is_lvalue_expr,
-          tok::kw___is_lvalue_reference,
-          tok::kw___is_member_function_pointer,
-          tok::kw___is_member_object_pointer,
-          tok::kw___is_member_pointer,
-          tok::kw___is_nothrow_assignable,
-          tok::kw___is_nothrow_constructible,
-          tok::kw___is_nothrow_convertible,
-          tok::kw___is_nothrow_destructible,
-          tok::kw___is_nullptr,
-          tok::kw___is_object,
-          tok::kw___is_pod,
-          tok::kw___is_pointer,
-          tok::kw___is_polymorphic,
-          tok::kw___is_reference,
-          tok::kw___is_referenceable,
-          tok::kw___is_rvalue_expr,
-          tok::kw___is_rvalue_reference,
-          tok::kw___is_same,
-          tok::kw___is_scalar,
-          tok::kw___is_scoped_enum,
-          tok::kw___is_sealed,
-          tok::kw___is_signed,
-          tok::kw___is_standard_layout,
-          tok::kw___is_trivial,
-          tok::kw___is_trivially_equality_comparable,
-          tok::kw___is_trivially_assignable,
-          tok::kw___is_trivially_constructible,
-          tok::kw___is_trivially_copyable,
-          tok::kw___is_unbounded_array,
-          tok::kw___is_union,
-          tok::kw___is_unsigned,
-          tok::kw___is_void,
-          tok::kw___is_volatile
-      ))
-    // GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
-    // name of struct templates, but some are keywords in GCC >= 4.3
-    // and Clang. Therefore, when we see the token sequence "struct
-    // X", make X into a normal identifier rather than a keyword, to
-    // allow libstdc++ 4.2 and libc++ to work properly.
-    TryKeywordIdentFallback(true);
-
   struct PreserveAtomicIdentifierInfoRAII {
     PreserveAtomicIdentifierInfoRAII(Token &Tok, bool Enabled)
         : AtomicII(nullptr) {
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index eb7447fa038e4..baea7df1d88d1 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1097,97 +1097,6 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
                                      isVectorLiteral, NotPrimaryExpression);
       }
 
-      // If this identifier was reverted from a token ID, and the next token
-      // is a parenthesis, this is likely to be a use of a type trait. Check
-      // those tokens.
-      else if (Next.is(tok::l_paren) && Tok.is(tok::identifier) &&
-               Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
-        IdentifierInfo *II = Tok.getIdentifierInfo();
-        // Build up the mapping of revertible type traits, for future use.
-        if (RevertibleTypeTraits.empty()) {
-#define RTT_JOIN(X,Y) X##Y
-#define REVERTIBLE_TYPE_TRAIT(Name)                         \
-          RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
-            = RTT_JOIN(tok::kw_,Name)
-
-          REVERTIBLE_TYPE_TRAIT(__is_abstract);
-          REVERTIBLE_TYPE_TRAIT(__is_aggregate);
-          REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
-          REVERTIBLE_TYPE_TRAIT(__is_array);
-          REVERTIBLE_TYPE_TRAIT(__is_assignable);
-          REVERTIBLE_TYPE_TRAIT(__is_base_of);
-          REVERTIBLE_TYPE_TRAIT(__is_bounded_array);
-          REVERTIBLE_TYPE_TRAIT(__is_class);
-          REVERTIBLE_TYPE_TRAIT(__is_complete_type);
-          REVERTIBLE_TYPE_TRAIT(__is_compound);
-          REVERTIBLE_TYPE_TRAIT(__is_const);
-          REVERTIBLE_TYPE_TRAIT(__is_constructible);
-          REVERTIBLE_TYPE_TRAIT(__is_convertible);
-          REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
-          REVERTIBLE_TYPE_TRAIT(__is_destructible);
-          REVERTIBLE_TYPE_TRAIT(__is_empty);
-          REVERTIBLE_TYPE_TRAIT(__is_enum);
-          REVERTIBLE_TYPE_TRAIT(__is_floating_point);
-          REVERTIBLE_TYPE_TRAIT(__is_final);
-          REVERTIBLE_TYPE_TRAIT(__is_function);
-          REVERTIBLE_TYPE_TRAIT(__is_fundamental);
-          REVERTIBLE_TYPE_TRAIT(__is_integral);
-          REVERTIBLE_TYPE_TRAIT(__is_interface_class);
-          REVERTIBLE_TYPE_TRAIT(__is_layout_compatible);
-          REVERTIBLE_TYPE_TRAIT(__is_literal);
-          REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
-          REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
-          REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
-          REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
-          REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
-          REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
-          REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
-          REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
-          REVERTIBLE_TYPE_TRAIT(__is_nullptr);
-          REVERTIBLE_TYPE_TRAIT(__is_object);
-          REVERTIBLE_TYPE_TRAIT(__is_pod);
-          REVERTIBLE_TYPE_TRAIT(__is_pointer);
-          REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
-          REVERTIBLE_TYPE_TRAIT(__is_reference);
-          REVERTIBLE_TYPE_TRAIT(__is_referenceable);
-          REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
-          REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
-          REVERTIBLE_TYPE_TRAIT(__is_same);
-          REVERTIBLE_TYPE_TRAIT(__is_scalar);
-          REVERTIBLE_TYPE_TRAIT(__is_scoped_enum);
-          REVERTIBLE_TYPE_TRAIT(__is_sealed);
-          REVERTIBLE_TYPE_TRAIT(__is_signed);
-          REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
-          REVERTIBLE_TYPE_TRAIT(__is_trivial);
-          REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
-          REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
-          REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
-          REVERTIBLE_TYPE_TRAIT(__is_unbounded_array);
-          REVERTIBLE_TYPE_TRAIT(__is_union);
-          REVERTIBLE_TYPE_TRAIT(__is_unsigned);
-          REVERTIBLE_TYPE_TRAIT(__is_void);
-          REVERTIBLE_TYPE_TRAIT(__is_volatile);
-          REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary);
-#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait)                                     \
-  REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
-#include "clang/Basic/TransformTypeTraits.def"
-#undef REVERTIBLE_TYPE_TRAIT
-#undef RTT_JOIN
-        }
-
-        // If we find that this is in fact the name of a type trait,
-        // update the token kind in place and parse again to treat it as
-        // the appropriate kind of type trait.
-        llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
-          = RevertibleTypeTraits.find(II);
-        if (Known != RevertibleTypeTraits.end()) {
-          Tok.setKind(Known->second);
-          return ParseCastExpression(ParseKind, isAddressOfOperand,
-                                     NotCastExpr, isTypeCast,
-                                     isVectorLiteral, NotPrimaryExpression);
-        }
-      }
-
       else if ((!ColonIsSacred && Next.is(tok::colon)) ||
                Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren,
                             tok::l_brace)) {
diff --git a/clang/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/clang/test/SemaCXX/libstdcxx_is_pod_hack.cpp
index a853a484707df..f787ee7092836 100644
--- a/clang/test/SemaCXX/libstdcxx_is_pod_hack.cpp
+++ b/clang/test/SemaCXX/libstdcxx_is_pod_hack.cpp
@@ -7,27 +7,27 @@
 // a keyword *unless* it is introduced following the struct keyword.
 
 template<typename T>
-struct __is_pod { // expected-warning {{keyword '__is_pod' will be made available as an identifier}}
-  __is_pod() {}
+struct __is_pod { // expected-warning {{using the name of the builtin '__is_pod' outside of a builtin invocation is deprecated}}
+  __is_pod() {} // expected-error {{expected member name or ';' after declaration specifier}}
 };
 
-__is_pod<int> ipi;
+__is_pod<int> ipi; // expected-warning {{using the name of the builtin '__is_pod' outside of a builtin invocation is deprecated}}
 
 // Ditto for __is_same.
 template<typename T>
-struct __is_same { // expected-warning {{keyword '__is_same' will be made available as an identifier}}
+struct __is_same { // expected-warning {{using the name of the builtin '__is_same' outside of a builtin invocation is deprecated}}
 };
 
-__is_same<int> isi;
+__is_same<int> isi; // expected-warning {{using the name of the builtin '__is_same' outside of a builtin invocation is deprecated}}
 
 // Another, similar egregious hack for __is_signed, which is a type
 // trait in Embarcadero's compiler but is used as an identifier in
 // libstdc++.
 struct test_is_signed {
-  static const bool __is_signed = true; // expected-warning {{keyword '__is_signed' will be made available as an identifier}}
+  static const bool __is_signed = true; // expected-warning {{using the name of the builtin '__is_signed' outside of a builtin invocation is deprecated}}
 };
 
-bool check_signed = test_is_signed::__is_signed;
+bool check_signed = test_is_signed::__is_signed; // expected-warning {{using the name of the builtin '__is_signed' outside of a builtin invocation is deprecated}}
 
 template<bool B> struct must_be_true {};
 template<> struct must_be_true<false>;

>From 908f40240cc2fa3d414afdf68d452df7a34b13cf Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Fri, 28 Jun 2024 21:01:46 +0300
Subject: [PATCH 2/5] Fix expected directives in tests

---
 clang/test/PCH/cxx-traits.cpp                 |   8 +-
 clang/test/PCH/cxx-traits.h                   | 102 ++---
 ..._is_trivially_equality_comparable_hack.cpp |  10 +-
 .../libstdcxx_is_nothrow_convertible_hack.cpp |  11 +-
 clang/test/SemaObjCXX/arc-libstdcxx.mm        |   7 +-
 clang/test/SemaObjCXX/arc-type-traits.mm      | 369 +++++++++---------
 .../test/SemaObjCXX/objc-weak-type-traits.mm  | 351 ++++++++---------
 7 files changed, 430 insertions(+), 428 deletions(-)

diff --git a/clang/test/PCH/cxx-traits.cpp b/clang/test/PCH/cxx-traits.cpp
index 01b9e9302d790..ca3f3ba5d35a2 100644
--- a/clang/test/PCH/cxx-traits.cpp
+++ b/clang/test/PCH/cxx-traits.cpp
@@ -2,14 +2,12 @@
 // RUN: %clang_cc1 -fms-extensions -include %S/cxx-traits.h -std=c++11 -fsyntax-only -verify %s
 
 // RUN: %clang_cc1 -fms-extensions -x c++-header -std=c++11 -emit-pch -o %t %S/cxx-traits.h
-// RUN: %clang_cc1 -fms-extensions -std=c++11 -include-pch %t -DPCH -fsyntax-only -verify %s
-
-#ifdef PCH
-// expected-no-diagnostics
-#endif
+// RUN: %clang_cc1 -fms-extensions -std=c++11 -include-pch %t -fsyntax-only -verify %s
 
 bool _Is_pod_comparator = n::__is_pod<int>::__value;
+// expected-warning at -1 {{using the name of the builtin '__is_pod' outside of a builtin invocation is deprecated}}
 bool _Is_empty_check = n::__is_empty<int>::__value;
+// expected-warning at -1 {{using the name of the builtin '__is_empty' outside of a builtin invocation is deprecated}}
 
 bool default_construct_int = n::is_trivially_constructible<int>::value;
 bool copy_construct_int = n::is_trivially_constructible<int, const int&>::value;
diff --git a/clang/test/PCH/cxx-traits.h b/clang/test/PCH/cxx-traits.h
index 0a4bd09c363e9..26d589b86fdca 100644
--- a/clang/test/PCH/cxx-traits.h
+++ b/clang/test/PCH/cxx-traits.h
@@ -3,12 +3,12 @@
 namespace n {
 
 template<typename _Tp>
-struct __is_pod { // expected-warning {{keyword '__is_pod' will be made available as an identifier for the remainder of the translation unit}}
+struct __is_pod { // expected-warning {{outside of a builtin invocation is deprecated}}
   enum { __value };
 };
 
 template<typename _Tp>
-struct __is_empty { // expected-warning {{keyword '__is_empty' will be made available as an identifier for the remainder of the translation unit}}
+struct __is_empty { // expected-warning {{outside of a builtin invocation is deprecated}}
   enum { __value };
 };
 
@@ -17,55 +17,55 @@ struct is_trivially_constructible {
   static const bool value = __is_trivially_constructible(T, Args...);
 };
 
-struct __is_abstract {};  // expected-warning {{made available}}
-struct __is_aggregate {}; // expected-warning {{made available}}
-struct __is_arithmetic {};  // expected-warning {{made available}}
-struct __is_array {};  // expected-warning {{made available}}
-struct __is_assignable {};  // expected-warning {{made available}}
-struct __is_base_of {};  // expected-warning {{made available}}
-struct __is_class {};  // expected-warning {{made available}}
-struct __is_complete_type {};  // expected-warning {{made available}}
-struct __is_compound {};  // expected-warning {{made available}}
-struct __is_const {};  // expected-warning {{made available}}
-struct __is_constructible {};  // expected-warning {{made available}}
-struct __is_convertible {};  // expected-warning {{made available}}
-struct __is_convertible_to {};  // expected-warning {{made available}}
-struct __is_destructible {};  // expected-warning {{made available}}
-struct __is_enum {};  // expected-warning {{made available}}
-struct __is_floating_point {};  // expected-warning {{made available}}
-struct __is_final {};  // expected-warning {{made available}}
-struct __is_function {};  // expected-warning {{made available}}
-struct __is_fundamental {};  // expected-warning {{made available}}
-struct __is_integral {};  // expected-warning {{made available}}
-struct __is_interface_class {};  // expected-warning {{made available}}
-struct __is_literal {};  // expected-warning {{made available}}
-struct __is_lvalue_expr {};  // expected-warning {{made available}}
-struct __is_lvalue_reference {};  // expected-warning {{made available}}
-struct __is_member_function_pointer {};  // expected-warning {{made available}}
-struct __is_member_object_pointer {};  // expected-warning {{made available}}
-struct __is_member_pointer {};  // expected-warning {{made available}}
-struct __is_nothrow_assignable {};  // expected-warning {{made available}}
-struct __is_nothrow_constructible {};  // expected-warning {{made available}}
-struct __is_nothrow_destructible {};  // expected-warning {{made available}}
-struct __is_object {};  // expected-warning {{made available}}
-struct __is_pointer {};  // expected-warning {{made available}}
-struct __is_polymorphic {};  // expected-warning {{made available}}
-struct __is_reference {};  // expected-warning {{made available}}
-struct __is_rvalue_expr {};  // expected-warning {{made available}}
-struct __is_rvalue_reference {};  // expected-warning {{made available}}
-struct __is_same {};  // expected-warning {{made available}}
-struct __is_scalar {};  // expected-warning {{made available}}
-struct __is_sealed {};  // expected-warning {{made available}}
-struct __is_signed {};  // expected-warning {{made available}}
-struct __is_standard_layout {};  // expected-warning {{made available}}
-struct __is_trivial {};  // expected-warning {{made available}}
-struct __is_trivially_assignable {};  // expected-warning {{made available}}
-struct __is_trivially_constructible {};  // expected-warning {{made available}}
-struct __is_trivially_copyable {};  // expected-warning {{made available}}
-struct __is_union {};  // expected-warning {{made available}}
-struct __is_unsigned {};  // expected-warning {{made available}}
-struct __is_void {};  // expected-warning {{made available}}
-struct __is_volatile {};  // expected-warning {{made available}}
+struct __is_abstract {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_aggregate {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_arithmetic {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_array {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_assignable {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_base_of {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_class {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_complete_type {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_compound {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_const {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_constructible {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_convertible {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_convertible_to {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_destructible {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_enum {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_floating_point {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_final {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_function {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_fundamental {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_integral {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_interface_class {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_literal {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_lvalue_expr {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_lvalue_reference {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_member_function_pointer {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_member_object_pointer {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_member_pointer {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_nothrow_assignable {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_nothrow_constructible {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_nothrow_destructible {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_object {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_pointer {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_polymorphic {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_reference {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_rvalue_expr {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_rvalue_reference {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_same {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_scalar {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_sealed {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_signed {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_standard_layout {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_trivial {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_trivially_assignable {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_trivially_constructible {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_trivially_copyable {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_union {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_unsigned {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_void {}; // expected-warning {{outside of a builtin invocation is deprecated}}
+struct __is_volatile {}; // expected-warning {{outside of a builtin invocation is deprecated}}
 
 
 }
diff --git a/clang/test/SemaCXX/libcxx_is_trivially_equality_comparable_hack.cpp b/clang/test/SemaCXX/libcxx_is_trivially_equality_comparable_hack.cpp
index 37adc5fc0b04b..22bab86f78484 100644
--- a/clang/test/SemaCXX/libcxx_is_trivially_equality_comparable_hack.cpp
+++ b/clang/test/SemaCXX/libcxx_is_trivially_equality_comparable_hack.cpp
@@ -7,8 +7,14 @@ struct Same {
 };
 
 template <class T>
-struct __is_trivially_equality_comparable { // expected-warning{{keyword '__is_trivially_equality_comparable' will be made available as an identifier for the remainder of the translation unit}}
+struct __is_trivially_equality_comparable {
+  // expected-warning at -1 {{using the name of the builtin '__is_trivially_equality_comparable' outside of a builtin invocation is deprecated}}
   using type = T;
 };
 
-using A = Same<__is_trivially_equality_comparable<int>::type, __is_trivially_equality_comparable<int>::type>;
+using A = Same<
+  __is_trivially_equality_comparable<int>::type,
+  // expected-warning at -1 {{using the name of the builtin '__is_trivially_equality_comparable' outside of a builtin invocation is deprecated}}
+  __is_trivially_equality_comparable<int>::type
+  // expected-warning at -1 {{using the name of the builtin '__is_trivially_equality_comparable' outside of a builtin invocation is deprecated}}
+>;
diff --git a/clang/test/SemaCXX/libstdcxx_is_nothrow_convertible_hack.cpp b/clang/test/SemaCXX/libstdcxx_is_nothrow_convertible_hack.cpp
index 9e84f0ab1c081..a9ef66474d3df 100644
--- a/clang/test/SemaCXX/libstdcxx_is_nothrow_convertible_hack.cpp
+++ b/clang/test/SemaCXX/libstdcxx_is_nothrow_convertible_hack.cpp
@@ -7,8 +7,15 @@ struct Same {
 };
 
 template <class T>
-struct __is_nothrow_convertible { // expected-warning{{keyword '__is_nothrow_convertible' will be made available as an identifier for the remainder of the translation unit}}
+struct __is_nothrow_convertible {
+  // expected-warning at -1 {{using the name of the builtin '__is_nothrow_convertible' outside of a builtin invocation is deprecated}}
   using type = T;
 };
 
-using A = Same<__is_nothrow_convertible<int>::type, __is_nothrow_convertible<int>::type>;
+using A = Same<
+  __is_nothrow_convertible<int>::type,
+  // expected-warning at -1 {{using the name of the builtin '__is_nothrow_convertible' outside of a builtin invocation is deprecated}}
+  __is_nothrow_convertible<int>::type
+  // expected-warning at -1 {{using the name of the builtin '__is_nothrow_convertible' outside of a builtin invocation is deprecated}}
+>;
+
diff --git a/clang/test/SemaObjCXX/arc-libstdcxx.mm b/clang/test/SemaObjCXX/arc-libstdcxx.mm
index 537e6b4279702..eed5bc6c56574 100644
--- a/clang/test/SemaObjCXX/arc-libstdcxx.mm
+++ b/clang/test/SemaObjCXX/arc-libstdcxx.mm
@@ -1,11 +1,16 @@
 // RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-arc-cxxlib=libstdc++ -fobjc-runtime-has-weak -verify %s
-// expected-no-diagnostics
 
 @interface A @end
 
 int check0[std::__is_scalar<__strong id>::__value? -1 : 1];
+// expected-warning at -1 {{using the name of the builtin '__is_scalar' outside of a builtin invocation is deprecated}}
 int check1[std::__is_scalar<__weak id>::__value? -1 : 1];
+// expected-warning at -1 {{using the name of the builtin '__is_scalar' outside of a builtin invocation is deprecated}}
 int check2[std::__is_scalar<__autoreleasing id>::__value? -1 : 1];
+// expected-warning at -1 {{using the name of the builtin '__is_scalar' outside of a builtin invocation is deprecated}}
 int check3[std::__is_scalar<__strong A*>::__value? -1 : 1];
+// expected-warning at -1 {{using the name of the builtin '__is_scalar' outside of a builtin invocation is deprecated}}
 int check4[std::__is_scalar<__weak A*>::__value? -1 : 1];
+// expected-warning at -1 {{using the name of the builtin '__is_scalar' outside of a builtin invocation is deprecated}}
 int check5[std::__is_scalar<__autoreleasing A*>::__value? -1 : 1];
+// expected-warning at -1 {{using the name of the builtin '__is_scalar' outside of a builtin invocation is deprecated}}
diff --git a/clang/test/SemaObjCXX/arc-type-traits.mm b/clang/test/SemaObjCXX/arc-type-traits.mm
index 25bc8b362140a..fd1fe07a8d58a 100644
--- a/clang/test/SemaObjCXX/arc-type-traits.mm
+++ b/clang/test/SemaObjCXX/arc-type-traits.mm
@@ -4,229 +4,220 @@
 // Check the results of the various type-trait query functions on
 // lifetime-qualified types in ARC.
 
-#define JOIN3(X,Y) X ## Y
-#define JOIN2(X,Y) JOIN3(X,Y)
-#define JOIN(X,Y) JOIN2(X,Y)
-
-#define TRAIT_IS_TRUE(Trait, Type) char JOIN2(Trait,__LINE__)[Trait(Type)? 1 : -1]
-#define TRAIT_IS_FALSE(Trait, Type) char JOIN2(Trait,__LINE__)[Trait(Type)? -1 : 1]
-#define TRAIT_IS_TRUE_2(Trait, Type1, Type2) char JOIN2(Trait,__LINE__)[Trait(Type1, Type2)? 1 : -1]
-#define TRAIT_IS_FALSE_2(Trait, Type1, Type2) char JOIN2(Trait,__LINE__)[Trait(Type1, Type2)? -1 : 1]
-
 struct HasStrong { id obj; };
 struct HasWeak { __weak id obj; };
 struct HasUnsafeUnretained { __unsafe_unretained id obj; };
 
 // __has_nothrow_assign
-TRAIT_IS_TRUE(__has_nothrow_assign, __strong id);
-TRAIT_IS_TRUE(__has_nothrow_assign, __weak id);
-TRAIT_IS_TRUE(__has_nothrow_assign, __autoreleasing id);
-TRAIT_IS_TRUE(__has_nothrow_assign, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_nothrow_assign, HasStrong);
-TRAIT_IS_TRUE(__has_nothrow_assign, HasWeak);
-TRAIT_IS_TRUE(__has_nothrow_assign, HasUnsafeUnretained);
+static_assert(__has_nothrow_assign(__strong id), "");
+static_assert(__has_nothrow_assign(__weak id), "");
+static_assert(__has_nothrow_assign(__autoreleasing id), "");
+static_assert(__has_nothrow_assign(__unsafe_unretained id), "");
+static_assert(__has_nothrow_assign(HasStrong), "");
+static_assert(__has_nothrow_assign(HasWeak), "");
+static_assert(__has_nothrow_assign(HasUnsafeUnretained), "");
 
 // __has_nothrow_copy
-TRAIT_IS_TRUE(__has_nothrow_copy, __strong id);
-TRAIT_IS_TRUE(__has_nothrow_copy, __weak id);
-TRAIT_IS_TRUE(__has_nothrow_copy, __autoreleasing id);
-TRAIT_IS_TRUE(__has_nothrow_copy, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_nothrow_copy, HasStrong);
-TRAIT_IS_TRUE(__has_nothrow_copy, HasWeak);
-TRAIT_IS_TRUE(__has_nothrow_copy, HasUnsafeUnretained);
+static_assert(__has_nothrow_copy(__strong id), "");
+static_assert(__has_nothrow_copy(__weak id), "");
+static_assert(__has_nothrow_copy(__autoreleasing id), "");
+static_assert(__has_nothrow_copy(__unsafe_unretained id), "");
+static_assert(__has_nothrow_copy(HasStrong), "");
+static_assert(__has_nothrow_copy(HasWeak), "");
+static_assert(__has_nothrow_copy(HasUnsafeUnretained), "");
 
 // __has_nothrow_constructor
-TRAIT_IS_TRUE(__has_nothrow_constructor, __strong id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, __weak id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, __autoreleasing id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, HasStrong);
-TRAIT_IS_TRUE(__has_nothrow_constructor, HasWeak);
-TRAIT_IS_TRUE(__has_nothrow_constructor, HasUnsafeUnretained);
+static_assert(__has_nothrow_constructor(__strong id), "");
+static_assert(__has_nothrow_constructor(__weak id), "");
+static_assert(__has_nothrow_constructor(__autoreleasing id), "");
+static_assert(__has_nothrow_constructor(__unsafe_unretained id), "");
+static_assert(__has_nothrow_constructor(HasStrong), "");
+static_assert(__has_nothrow_constructor(HasWeak), "");
+static_assert(__has_nothrow_constructor(HasUnsafeUnretained), "");
 
 // __has_trivial_assign
-TRAIT_IS_FALSE(__has_trivial_assign, __strong id);
-TRAIT_IS_FALSE(__has_trivial_assign, __weak id);
-TRAIT_IS_FALSE(__has_trivial_assign, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_assign, __unsafe_unretained id);
-TRAIT_IS_FALSE(__has_trivial_assign, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_assign, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_assign, HasUnsafeUnretained);
+static_assert(!__has_trivial_assign(__strong id), "");
+static_assert(!__has_trivial_assign(__weak id), "");
+static_assert(!__has_trivial_assign(__autoreleasing id), "");
+static_assert(__has_trivial_assign(__unsafe_unretained id), "");
+static_assert(!__has_trivial_assign(HasStrong), "");
+static_assert(!__has_trivial_assign(HasWeak), "");
+static_assert(__has_trivial_assign(HasUnsafeUnretained), "");
 
 // __has_trivial_copy
-TRAIT_IS_FALSE(__has_trivial_copy, __strong id);
-TRAIT_IS_FALSE(__has_trivial_copy, __weak id);
-TRAIT_IS_FALSE(__has_trivial_copy, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_copy, __unsafe_unretained id);
-TRAIT_IS_FALSE(__has_trivial_copy, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_copy, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_copy, HasUnsafeUnretained);
+static_assert(!__has_trivial_copy(__strong id), "");
+static_assert(!__has_trivial_copy(__weak id), "");
+static_assert(!__has_trivial_copy(__autoreleasing id), "");
+static_assert(__has_trivial_copy(__unsafe_unretained id), "");
+static_assert(!__has_trivial_copy(HasStrong), "");
+static_assert(!__has_trivial_copy(HasWeak), "");
+static_assert(__has_trivial_copy(HasUnsafeUnretained), "");
 
 // __has_trivial_constructor
-TRAIT_IS_FALSE(__has_trivial_constructor, __strong id);
-TRAIT_IS_FALSE(__has_trivial_constructor, __weak id);
-TRAIT_IS_FALSE(__has_trivial_constructor, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_constructor, __unsafe_unretained id);
-TRAIT_IS_FALSE(__has_trivial_constructor, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_constructor, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_constructor, HasUnsafeUnretained);
+static_assert(!__has_trivial_constructor(__strong id), "");
+static_assert(!__has_trivial_constructor(__weak id), "");
+static_assert(!__has_trivial_constructor(__autoreleasing id), "");
+static_assert(__has_trivial_constructor(__unsafe_unretained id), "");
+static_assert(!__has_trivial_constructor(HasStrong), "");
+static_assert(!__has_trivial_constructor(HasWeak), "");
+static_assert(__has_trivial_constructor(HasUnsafeUnretained), "");
 
 // __has_trivial_destructor
-TRAIT_IS_FALSE(__has_trivial_destructor, __strong id);
-TRAIT_IS_FALSE(__has_trivial_destructor, __weak id);
-TRAIT_IS_TRUE(__has_trivial_destructor, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_destructor, __unsafe_unretained id);
-TRAIT_IS_FALSE(__has_trivial_destructor, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_destructor, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_destructor, HasUnsafeUnretained);
+static_assert(!__has_trivial_destructor(__strong id), "");
+static_assert(!__has_trivial_destructor(__weak id), "");
+static_assert(__has_trivial_destructor(__autoreleasing id), "");
+static_assert(__has_trivial_destructor(__unsafe_unretained id), "");
+static_assert(!__has_trivial_destructor(HasStrong), "");
+static_assert(!__has_trivial_destructor(HasWeak), "");
+static_assert(__has_trivial_destructor(HasUnsafeUnretained), "");
 
 // __is_literal
-TRAIT_IS_TRUE(__is_literal, __strong id);
-TRAIT_IS_TRUE(__is_literal, __weak id);
-TRAIT_IS_TRUE(__is_literal, __autoreleasing id);
-TRAIT_IS_TRUE(__is_literal, __unsafe_unretained id);
+static_assert(__is_literal(__strong id), "");
+static_assert(__is_literal(__weak id), "");
+static_assert(__is_literal(__autoreleasing id), "");
+static_assert(__is_literal(__unsafe_unretained id), "");
 
 // __is_literal_type
-TRAIT_IS_TRUE(__is_literal_type, __strong id);
-TRAIT_IS_TRUE(__is_literal_type, __weak id);
-TRAIT_IS_TRUE(__is_literal_type, __autoreleasing id);
-TRAIT_IS_TRUE(__is_literal_type, __unsafe_unretained id);
+static_assert(__is_literal_type(__strong id), "");
+static_assert(__is_literal_type(__weak id), "");
+static_assert(__is_literal_type(__autoreleasing id), "");
+static_assert(__is_literal_type(__unsafe_unretained id), "");
 
 // __is_pod
-TRAIT_IS_FALSE(__is_pod, __strong id);
-TRAIT_IS_FALSE(__is_pod, __weak id);
-TRAIT_IS_FALSE(__is_pod, __autoreleasing id);
-TRAIT_IS_TRUE(__is_pod, __unsafe_unretained id);
-TRAIT_IS_FALSE(__is_pod, HasStrong);
-TRAIT_IS_FALSE(__is_pod, HasWeak);
-TRAIT_IS_TRUE(__is_pod, HasUnsafeUnretained);
+static_assert(!__is_pod(__strong id), "");
+static_assert(!__is_pod(__weak id), "");
+static_assert(!__is_pod(__autoreleasing id), "");
+static_assert(__is_pod(__unsafe_unretained id), "");
+static_assert(!__is_pod(HasStrong), "");
+static_assert(!__is_pod(HasWeak), "");
+static_assert(__is_pod(HasUnsafeUnretained), "");
 
 // __is_trivial
-TRAIT_IS_FALSE(__is_trivial, __strong id);
-TRAIT_IS_FALSE(__is_trivial, __weak id);
-TRAIT_IS_FALSE(__is_trivial, __autoreleasing id);
-TRAIT_IS_TRUE(__is_trivial, __unsafe_unretained id);
-TRAIT_IS_FALSE(__is_trivial, HasStrong);
-TRAIT_IS_FALSE(__is_trivial, HasWeak);
-TRAIT_IS_TRUE(__is_trivial, HasUnsafeUnretained);
+static_assert(!__is_trivial(__strong id), "");
+static_assert(!__is_trivial(__weak id), "");
+static_assert(!__is_trivial(__autoreleasing id), "");
+static_assert(__is_trivial(__unsafe_unretained id), "");
+static_assert(!__is_trivial(HasStrong), "");
+static_assert(!__is_trivial(HasWeak), "");
+static_assert(__is_trivial(HasUnsafeUnretained), "");
 
 // __is_scalar
-TRAIT_IS_FALSE(__is_scalar, __strong id);
-TRAIT_IS_FALSE(__is_scalar, __weak id);
-TRAIT_IS_FALSE(__is_scalar, __autoreleasing id);
-TRAIT_IS_TRUE(__is_scalar, __unsafe_unretained id);
+static_assert(!__is_scalar(__strong id), "");
+static_assert(!__is_scalar(__weak id), "");
+static_assert(!__is_scalar(__autoreleasing id), "");
+static_assert(__is_scalar(__unsafe_unretained id), "");
 
 // __is_standard_layout
-TRAIT_IS_TRUE(__is_standard_layout, __strong id);
-TRAIT_IS_TRUE(__is_standard_layout, __weak id);
-TRAIT_IS_TRUE(__is_standard_layout, __autoreleasing id);
-TRAIT_IS_TRUE(__is_standard_layout, __unsafe_unretained id);
+static_assert(__is_standard_layout(__strong id), "");
+static_assert(__is_standard_layout(__weak id), "");
+static_assert(__is_standard_layout(__autoreleasing id), "");
+static_assert(__is_standard_layout(__unsafe_unretained id), "");
 
 // __is_trivally_assignable
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __strong id&, __unsafe_unretained id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __unsafe_unretained id&&);
-
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __autoreleasing id&, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __unsafe_unretained id&&);
-
-TRAIT_IS_FALSE_2(__is_trivially_assignable, HasStrong&, HasStrong);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, HasStrong&, HasStrong&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, HasWeak&, HasWeak);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, HasWeak&, HasWeak&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, HasUnsafeUnretained&, HasUnsafeUnretained);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, HasUnsafeUnretained&, HasUnsafeUnretained&&);
+static_assert(!__is_trivially_assignable(__strong id&, __strong id), "");
+static_assert(!__is_trivially_assignable(__strong id&, __weak id), "");
+static_assert(!__is_trivially_assignable(__strong id&, __autoreleasing id), "");
+static_assert(!__is_trivially_assignable(__strong id&, __unsafe_unretained id), "");
+static_assert(!__is_trivially_assignable(__strong id&, __strong id&&), "");
+static_assert(!__is_trivially_assignable(__strong id&, __weak id&&), "");
+static_assert(!__is_trivially_assignable(__strong id&, __autoreleasing id&&), "");
+static_assert(!__is_trivially_assignable(__strong id&, __unsafe_unretained id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __strong id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __weak id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __autoreleasing id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __unsafe_unretained id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __strong id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __weak id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __autoreleasing id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __unsafe_unretained id&&), "");
+
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __strong id), "");
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __weak id), "");
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __autoreleasing id), "");
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __unsafe_unretained id), "");
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __strong id&&), "");
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __weak id&&), "");
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __autoreleasing id&&), "");
+static_assert(!__is_trivially_assignable(__autoreleasing id&, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __strong id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __weak id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __autoreleasing id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __unsafe_unretained id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __strong id&&), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __weak id&&), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __autoreleasing id&&), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __unsafe_unretained id&&), "");
+
+static_assert(!__is_trivially_assignable(HasStrong&, HasStrong), "");
+static_assert(!__is_trivially_assignable(HasStrong&, HasStrong&&), "");
+static_assert(!__is_trivially_assignable(HasWeak&, HasWeak), "");
+static_assert(!__is_trivially_assignable(HasWeak&, HasWeak&&), "");
+static_assert(__is_trivially_assignable(HasUnsafeUnretained&, HasUnsafeUnretained), "");
+static_assert(__is_trivially_assignable(HasUnsafeUnretained&, HasUnsafeUnretained&&), "");
 
 // __is_trivally_constructible
-TRAIT_IS_FALSE(__is_trivially_constructible, __strong id);
-TRAIT_IS_FALSE(__is_trivially_constructible, __weak id);
-TRAIT_IS_FALSE(__is_trivially_constructible, __autoreleasing id);
-TRAIT_IS_TRUE(__is_trivially_constructible, __unsafe_unretained id);
-
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __strong id, __unsafe_unretained id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __unsafe_unretained id&&);
-
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __autoreleasing id, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __unsafe_unretained id&&);
-
-TRAIT_IS_FALSE_2(__is_trivially_constructible, HasStrong, HasStrong);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, HasStrong, HasStrong&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, HasWeak, HasWeak);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, HasWeak, HasWeak&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, HasUnsafeUnretained, HasUnsafeUnretained);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, HasUnsafeUnretained, HasUnsafeUnretained&&);
+static_assert(!__is_trivially_constructible(__strong id), "");
+static_assert(!__is_trivially_constructible(__weak id), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id), "");
+
+static_assert(!__is_trivially_constructible(__strong id, __strong id), "");
+static_assert(!__is_trivially_constructible(__strong id, __weak id), "");
+static_assert(!__is_trivially_constructible(__strong id, __autoreleasing id), "");
+static_assert(!__is_trivially_constructible(__strong id, __unsafe_unretained id), "");
+static_assert(!__is_trivially_constructible(__strong id, __strong id&&), "");
+static_assert(!__is_trivially_constructible(__strong id, __weak id&&), "");
+static_assert(!__is_trivially_constructible(__strong id, __autoreleasing id&&), "");
+static_assert(!__is_trivially_constructible(__strong id, __unsafe_unretained id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __strong id), "");
+static_assert(!__is_trivially_constructible(__weak id, __weak id), "");
+static_assert(!__is_trivially_constructible(__weak id, __autoreleasing id), "");
+static_assert(!__is_trivially_constructible(__weak id, __unsafe_unretained id), "");
+static_assert(!__is_trivially_constructible(__weak id, __strong id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __weak id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __autoreleasing id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __unsafe_unretained id&&), "");
+
+static_assert(!__is_trivially_constructible(__autoreleasing id, __strong id), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id, __weak id), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id, __autoreleasing id), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id, __unsafe_unretained id), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id, __strong id&&), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id, __weak id&&), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id, __autoreleasing id&&), "");
+static_assert(!__is_trivially_constructible(__autoreleasing id, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __strong id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __weak id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __autoreleasing id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __unsafe_unretained id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __strong id&&), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __weak id&&), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __autoreleasing id&&), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __unsafe_unretained id&&), "");
+
+static_assert(!__is_trivially_constructible(HasStrong, HasStrong), "");
+static_assert(!__is_trivially_constructible(HasStrong, HasStrong&&), "");
+static_assert(!__is_trivially_constructible(HasWeak, HasWeak), "");
+static_assert(!__is_trivially_constructible(HasWeak, HasWeak&&), "");
+static_assert(__is_trivially_constructible(HasUnsafeUnretained, HasUnsafeUnretained), "");
+static_assert(__is_trivially_constructible(HasUnsafeUnretained, HasUnsafeUnretained&&), "");
 
 // __is_trivially_relocatable
-TRAIT_IS_TRUE(__is_trivially_relocatable, __strong id);
-TRAIT_IS_FALSE(__is_trivially_relocatable, __weak id);
-TRAIT_IS_TRUE(__is_trivially_relocatable, __autoreleasing id);
-TRAIT_IS_TRUE(__is_trivially_relocatable, __unsafe_unretained id);
-TRAIT_IS_TRUE(__is_trivially_relocatable, HasStrong);
-TRAIT_IS_FALSE(__is_trivially_relocatable, HasWeak);
-TRAIT_IS_TRUE(__is_trivially_relocatable, HasUnsafeUnretained);
+static_assert(__is_trivially_relocatable(__strong id), "");
+static_assert(!__is_trivially_relocatable(__weak id), "");
+static_assert(__is_trivially_relocatable(__autoreleasing id), "");
+static_assert(__is_trivially_relocatable(__unsafe_unretained id), "");
+static_assert(__is_trivially_relocatable(HasStrong), "");
+static_assert(!__is_trivially_relocatable(HasWeak), "");
+static_assert(__is_trivially_relocatable(HasUnsafeUnretained), "");
 
 // __is_bitwise_cloneable
-TRAIT_IS_FALSE(__is_bitwise_cloneable, __strong id);
-TRAIT_IS_FALSE(__is_bitwise_cloneable, __weak id);
-TRAIT_IS_FALSE(__is_bitwise_cloneable, __autoreleasing id);
-TRAIT_IS_TRUE(__is_trivial, __unsafe_unretained id);
-TRAIT_IS_FALSE(__is_bitwise_cloneable, HasStrong);
-TRAIT_IS_FALSE(__is_bitwise_cloneable, HasWeak);
-TRAIT_IS_TRUE(__is_bitwise_cloneable, HasUnsafeUnretained);
+static_assert(!__is_bitwise_cloneable(__strong id), "");
+static_assert(!__is_bitwise_cloneable(__weak id), "");
+static_assert(!__is_bitwise_cloneable(__autoreleasing id), "");
+static_assert(__is_bitwise_cloneable(__unsafe_unretained id), "");
+static_assert(!__is_bitwise_cloneable(HasStrong), "");
+static_assert(!__is_bitwise_cloneable(HasWeak), "");
+static_assert(__is_bitwise_cloneable(HasUnsafeUnretained), "");
diff --git a/clang/test/SemaObjCXX/objc-weak-type-traits.mm b/clang/test/SemaObjCXX/objc-weak-type-traits.mm
index e8f3e637ac272..3e46f4881284c 100644
--- a/clang/test/SemaObjCXX/objc-weak-type-traits.mm
+++ b/clang/test/SemaObjCXX/objc-weak-type-traits.mm
@@ -4,216 +4,211 @@
 // Check the results of the various type-trait query functions on
 // lifetime-qualified types in ObjC Weak.
 
-#define TRAIT_IS_TRUE(Trait, Type) static_assert(Trait(Type), "")
-#define TRAIT_IS_FALSE(Trait, Type) static_assert(!Trait(Type), "")
-#define TRAIT_IS_TRUE_2(Trait, Type1, Type2) static_assert(Trait(Type1, Type2), "")
-#define TRAIT_IS_FALSE_2(Trait, Type1, Type2) static_assert(!Trait(Type1, Type2), "")
-
 struct HasStrong { id obj; };
 struct HasWeak { __weak id obj; };
 struct HasUnsafeUnretained { __unsafe_unretained id obj; };
 
 // __has_nothrow_assign
-TRAIT_IS_TRUE(__has_nothrow_assign, __strong id);
-TRAIT_IS_TRUE(__has_nothrow_assign, __weak id);
-TRAIT_IS_TRUE(__has_nothrow_assign, __autoreleasing id);
-TRAIT_IS_TRUE(__has_nothrow_assign, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_nothrow_assign, HasStrong);
-TRAIT_IS_TRUE(__has_nothrow_assign, HasWeak);
-TRAIT_IS_TRUE(__has_nothrow_assign, HasUnsafeUnretained);
+static_assert(__has_nothrow_assign(__strong id), "");
+static_assert(__has_nothrow_assign(__weak id), "");
+static_assert(__has_nothrow_assign(__autoreleasing id), "");
+static_assert(__has_nothrow_assign(__unsafe_unretained id), "");
+static_assert(__has_nothrow_assign(HasStrong), "");
+static_assert(__has_nothrow_assign(HasWeak), "");
+static_assert(__has_nothrow_assign(HasUnsafeUnretained), "");
 
 // __has_nothrow_copy
-TRAIT_IS_TRUE(__has_nothrow_copy, __strong id);
-TRAIT_IS_TRUE(__has_nothrow_copy, __weak id);
-TRAIT_IS_TRUE(__has_nothrow_copy, __autoreleasing id);
-TRAIT_IS_TRUE(__has_nothrow_copy, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_nothrow_copy, HasStrong);
-TRAIT_IS_TRUE(__has_nothrow_copy, HasWeak);
-TRAIT_IS_TRUE(__has_nothrow_copy, HasUnsafeUnretained);
+static_assert(__has_nothrow_copy(__strong id), "");
+static_assert(__has_nothrow_copy(__weak id), "");
+static_assert(__has_nothrow_copy(__autoreleasing id), "");
+static_assert(__has_nothrow_copy(__unsafe_unretained id), "");
+static_assert(__has_nothrow_copy(HasStrong), "");
+static_assert(__has_nothrow_copy(HasWeak), "");
+static_assert(__has_nothrow_copy(HasUnsafeUnretained), "");
 
 // __has_nothrow_constructor
-TRAIT_IS_TRUE(__has_nothrow_constructor, __strong id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, __weak id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, __autoreleasing id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_nothrow_constructor, HasStrong);
-TRAIT_IS_TRUE(__has_nothrow_constructor, HasWeak);
-TRAIT_IS_TRUE(__has_nothrow_constructor, HasUnsafeUnretained);
+static_assert(__has_nothrow_constructor(__strong id), "");
+static_assert(__has_nothrow_constructor(__weak id), "");
+static_assert(__has_nothrow_constructor(__autoreleasing id), "");
+static_assert(__has_nothrow_constructor(__unsafe_unretained id), "");
+static_assert(__has_nothrow_constructor(HasStrong), "");
+static_assert(__has_nothrow_constructor(HasWeak), "");
+static_assert(__has_nothrow_constructor(HasUnsafeUnretained), "");
 
 // __has_trivial_assign
-TRAIT_IS_TRUE(__has_trivial_assign, __strong id);
-TRAIT_IS_FALSE(__has_trivial_assign, __weak id);
-TRAIT_IS_TRUE(__has_trivial_assign, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_assign, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_trivial_assign, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_assign, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_assign, HasUnsafeUnretained);
+static_assert(__has_trivial_assign(__strong id), "");
+static_assert(!__has_trivial_assign(__weak id), "");
+static_assert(__has_trivial_assign(__autoreleasing id), "");
+static_assert(__has_trivial_assign(__unsafe_unretained id), "");
+static_assert(__has_trivial_assign(HasStrong), "");
+static_assert(!__has_trivial_assign(HasWeak), "");
+static_assert(__has_trivial_assign(HasUnsafeUnretained), "");
 
 // __has_trivial_copy
-TRAIT_IS_TRUE(__has_trivial_copy, __strong id);
-TRAIT_IS_FALSE(__has_trivial_copy, __weak id);
-TRAIT_IS_TRUE(__has_trivial_copy, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_copy, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_trivial_copy, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_copy, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_copy, HasUnsafeUnretained);
+static_assert(__has_trivial_copy(__strong id), "");
+static_assert(!__has_trivial_copy(__weak id), "");
+static_assert(__has_trivial_copy(__autoreleasing id), "");
+static_assert(__has_trivial_copy(__unsafe_unretained id), "");
+static_assert(__has_trivial_copy(HasStrong), "");
+static_assert(!__has_trivial_copy(HasWeak), "");
+static_assert(__has_trivial_copy(HasUnsafeUnretained), "");
 
 // __has_trivial_constructor
-TRAIT_IS_TRUE(__has_trivial_constructor, __strong id);
-TRAIT_IS_FALSE(__has_trivial_constructor, __weak id);
-TRAIT_IS_TRUE(__has_trivial_constructor, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_constructor, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_trivial_constructor, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_constructor, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_constructor, HasUnsafeUnretained);
+static_assert(__has_trivial_constructor(__strong id), "");
+static_assert(!__has_trivial_constructor(__weak id), "");
+static_assert(__has_trivial_constructor(__autoreleasing id), "");
+static_assert(__has_trivial_constructor(__unsafe_unretained id), "");
+static_assert(__has_trivial_constructor(HasStrong), "");
+static_assert(!__has_trivial_constructor(HasWeak), "");
+static_assert(__has_trivial_constructor(HasUnsafeUnretained), "");
 
 // __has_trivial_destructor
-TRAIT_IS_TRUE(__has_trivial_destructor, __strong id);
-TRAIT_IS_FALSE(__has_trivial_destructor, __weak id);
-TRAIT_IS_TRUE(__has_trivial_destructor, __autoreleasing id);
-TRAIT_IS_TRUE(__has_trivial_destructor, __unsafe_unretained id);
-TRAIT_IS_TRUE(__has_trivial_destructor, HasStrong);
-TRAIT_IS_FALSE(__has_trivial_destructor, HasWeak);
-TRAIT_IS_TRUE(__has_trivial_destructor, HasUnsafeUnretained);
+static_assert(__has_trivial_destructor(__strong id), "");
+static_assert(!__has_trivial_destructor(__weak id), "");
+static_assert(__has_trivial_destructor(__autoreleasing id), "");
+static_assert(__has_trivial_destructor(__unsafe_unretained id), "");
+static_assert(__has_trivial_destructor(HasStrong), "");
+static_assert(!__has_trivial_destructor(HasWeak), "");
+static_assert(__has_trivial_destructor(HasUnsafeUnretained), "");
 
 // __is_literal
-TRAIT_IS_TRUE(__is_literal, __strong id);
-TRAIT_IS_TRUE(__is_literal, __weak id);
-TRAIT_IS_TRUE(__is_literal, __autoreleasing id);
-TRAIT_IS_TRUE(__is_literal, __unsafe_unretained id);
+static_assert(__is_literal(__strong id), "");
+static_assert(__is_literal(__weak id), "");
+static_assert(__is_literal(__autoreleasing id), "");
+static_assert(__is_literal(__unsafe_unretained id), "");
 
 // __is_literal_type
-TRAIT_IS_TRUE(__is_literal_type, __strong id);
-TRAIT_IS_TRUE(__is_literal_type, __weak id);
-TRAIT_IS_TRUE(__is_literal_type, __autoreleasing id);
-TRAIT_IS_TRUE(__is_literal_type, __unsafe_unretained id);
+static_assert(__is_literal_type(__strong id), "");
+static_assert(__is_literal_type(__weak id), "");
+static_assert(__is_literal_type(__autoreleasing id), "");
+static_assert(__is_literal_type(__unsafe_unretained id), "");
 
 // __is_pod
-TRAIT_IS_TRUE(__is_pod, __strong id);
-TRAIT_IS_FALSE(__is_pod, __weak id);
-TRAIT_IS_TRUE(__is_pod, __autoreleasing id);
-TRAIT_IS_TRUE(__is_pod, __unsafe_unretained id);
-TRAIT_IS_TRUE(__is_pod, HasStrong);
-TRAIT_IS_FALSE(__is_pod, HasWeak);
-TRAIT_IS_TRUE(__is_pod, HasUnsafeUnretained);
+static_assert(__is_pod(__strong id), "");
+static_assert(!__is_pod(__weak id), "");
+static_assert(__is_pod(__autoreleasing id), "");
+static_assert(__is_pod(__unsafe_unretained id), "");
+static_assert(__is_pod(HasStrong), "");
+static_assert(!__is_pod(HasWeak), "");
+static_assert(__is_pod(HasUnsafeUnretained), "");
 
 // __is_trivial
-TRAIT_IS_TRUE(__is_trivial, __strong id);
-TRAIT_IS_FALSE(__is_trivial, __weak id);
-TRAIT_IS_TRUE(__is_trivial, __autoreleasing id);
-TRAIT_IS_TRUE(__is_trivial, __unsafe_unretained id);
-TRAIT_IS_TRUE(__is_trivial, HasStrong);
-TRAIT_IS_FALSE(__is_trivial, HasWeak);
-TRAIT_IS_TRUE(__is_trivial, HasUnsafeUnretained);
+static_assert(__is_trivial(__strong id), "");
+static_assert(!__is_trivial(__weak id), "");
+static_assert(__is_trivial(__autoreleasing id), "");
+static_assert(__is_trivial(__unsafe_unretained id), "");
+static_assert(__is_trivial(HasStrong), "");
+static_assert(!__is_trivial(HasWeak), "");
+static_assert(__is_trivial(HasUnsafeUnretained), "");
 
 // __is_scalar
-TRAIT_IS_TRUE(__is_scalar, __strong id);
-TRAIT_IS_FALSE(__is_scalar, __weak id);
-TRAIT_IS_TRUE(__is_scalar, __autoreleasing id);
-TRAIT_IS_TRUE(__is_scalar, __unsafe_unretained id);
+static_assert(__is_scalar(__strong id), "");
+static_assert(!__is_scalar(__weak id), "");
+static_assert(__is_scalar(__autoreleasing id), "");
+static_assert(__is_scalar(__unsafe_unretained id), "");
 
 // __is_standard_layout
-TRAIT_IS_TRUE(__is_standard_layout, __strong id);
-TRAIT_IS_TRUE(__is_standard_layout, __weak id);
-TRAIT_IS_TRUE(__is_standard_layout, __autoreleasing id);
-TRAIT_IS_TRUE(__is_standard_layout, __unsafe_unretained id);
+static_assert(__is_standard_layout(__strong id), "");
+static_assert(__is_standard_layout(__weak id), "");
+static_assert(__is_standard_layout(__autoreleasing id), "");
+static_assert(__is_standard_layout(__unsafe_unretained id), "");
 
 // __is_trivally_assignable
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __strong id&, __unsafe_unretained id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, __weak id&, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __autoreleasing id&, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, __unsafe_unretained id&, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_assignable, HasStrong&, HasStrong);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, HasStrong&, HasStrong&&);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, HasWeak&, HasWeak);
-TRAIT_IS_FALSE_2(__is_trivially_assignable, HasWeak&, HasWeak&&);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, HasUnsafeUnretained&, HasUnsafeUnretained);
-TRAIT_IS_TRUE_2(__is_trivially_assignable, HasUnsafeUnretained&, HasUnsafeUnretained&&);
+static_assert(__is_trivially_assignable(__strong id&, __strong id), "");
+static_assert(__is_trivially_assignable(__strong id&, __weak id), "");
+static_assert(__is_trivially_assignable(__strong id&, __autoreleasing id), "");
+static_assert(__is_trivially_assignable(__strong id&, __unsafe_unretained id), "");
+static_assert(__is_trivially_assignable(__strong id&, __strong id&&), "");
+static_assert(__is_trivially_assignable(__strong id&, __weak id&&), "");
+static_assert(__is_trivially_assignable(__strong id&, __autoreleasing id&&), "");
+static_assert(__is_trivially_assignable(__strong id&, __unsafe_unretained id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __strong id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __weak id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __autoreleasing id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __unsafe_unretained id), "");
+static_assert(!__is_trivially_assignable(__weak id&, __strong id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __weak id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __autoreleasing id&&), "");
+static_assert(!__is_trivially_assignable(__weak id&, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_assignable(__autoreleasing id&, __strong id), "");
+static_assert(__is_trivially_assignable(__autoreleasing id&, __weak id), "");
+static_assert(__is_trivially_assignable(__autoreleasing id&, __autoreleasing id), "");
+static_assert(__is_trivially_assignable(__autoreleasing id&, __unsafe_unretained id), "");
+static_assert(__is_trivially_assignable(__autoreleasing id&, __strong id&&), "");
+static_assert(__is_trivially_assignable(__autoreleasing id&, __weak id&&), "");
+static_assert(__is_trivially_assignable(__autoreleasing id&, __autoreleasing id&&), "");
+static_assert(__is_trivially_assignable(__autoreleasing id&, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __strong id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __weak id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __autoreleasing id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __unsafe_unretained id), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __strong id&&), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __weak id&&), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __autoreleasing id&&), "");
+static_assert(__is_trivially_assignable(__unsafe_unretained id&, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_assignable(HasStrong&, HasStrong), "");
+static_assert(__is_trivially_assignable(HasStrong&, HasStrong&&), "");
+static_assert(!__is_trivially_assignable(HasWeak&, HasWeak), "");
+static_assert(!__is_trivially_assignable(HasWeak&, HasWeak&&), "");
+static_assert(__is_trivially_assignable(HasUnsafeUnretained&, HasUnsafeUnretained), "");
+static_assert(__is_trivially_assignable(HasUnsafeUnretained&, HasUnsafeUnretained&&), "");
 
 // __is_trivally_constructible
-TRAIT_IS_TRUE(__is_trivially_constructible, __strong id);
-TRAIT_IS_FALSE(__is_trivially_constructible, __weak id);
-TRAIT_IS_TRUE(__is_trivially_constructible, __autoreleasing id);
-TRAIT_IS_TRUE(__is_trivially_constructible, __unsafe_unretained id);
-
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __strong id, __unsafe_unretained id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __strong id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __weak id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __autoreleasing id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __unsafe_unretained id);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __strong id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __weak id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __autoreleasing id&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, __weak id, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __autoreleasing id, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __strong id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __weak id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __autoreleasing id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __unsafe_unretained id);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __strong id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __weak id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __autoreleasing id&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, __unsafe_unretained id, __unsafe_unretained id&&);
-
-TRAIT_IS_TRUE_2(__is_trivially_constructible, HasStrong, HasStrong);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, HasStrong, HasStrong&&);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, HasWeak, HasWeak);
-TRAIT_IS_FALSE_2(__is_trivially_constructible, HasWeak, HasWeak&&);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, HasUnsafeUnretained, HasUnsafeUnretained);
-TRAIT_IS_TRUE_2(__is_trivially_constructible, HasUnsafeUnretained, HasUnsafeUnretained&&);
+static_assert(__is_trivially_constructible(__strong id), "");
+static_assert(!__is_trivially_constructible(__weak id), "");
+static_assert(__is_trivially_constructible(__autoreleasing id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id), "");
+
+static_assert(__is_trivially_constructible(__strong id, __strong id), "");
+static_assert(__is_trivially_constructible(__strong id, __weak id), "");
+static_assert(__is_trivially_constructible(__strong id, __autoreleasing id), "");
+static_assert(__is_trivially_constructible(__strong id, __unsafe_unretained id), "");
+static_assert(__is_trivially_constructible(__strong id, __strong id&&), "");
+static_assert(__is_trivially_constructible(__strong id, __weak id&&), "");
+static_assert(__is_trivially_constructible(__strong id, __autoreleasing id&&), "");
+static_assert(__is_trivially_constructible(__strong id, __unsafe_unretained id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __strong id), "");
+static_assert(!__is_trivially_constructible(__weak id, __weak id), "");
+static_assert(!__is_trivially_constructible(__weak id, __autoreleasing id), "");
+static_assert(!__is_trivially_constructible(__weak id, __unsafe_unretained id), "");
+static_assert(!__is_trivially_constructible(__weak id, __strong id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __weak id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __autoreleasing id&&), "");
+static_assert(!__is_trivially_constructible(__weak id, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_constructible(__autoreleasing id, __strong id), "");
+static_assert(__is_trivially_constructible(__autoreleasing id, __weak id), "");
+static_assert(__is_trivially_constructible(__autoreleasing id, __autoreleasing id), "");
+static_assert(__is_trivially_constructible(__autoreleasing id, __unsafe_unretained id), "");
+static_assert(__is_trivially_constructible(__autoreleasing id, __strong id&&), "");
+static_assert(__is_trivially_constructible(__autoreleasing id, __weak id&&), "");
+static_assert(__is_trivially_constructible(__autoreleasing id, __autoreleasing id&&), "");
+static_assert(__is_trivially_constructible(__autoreleasing id, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __strong id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __weak id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __autoreleasing id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __unsafe_unretained id), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __strong id&&), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __weak id&&), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __autoreleasing id&&), "");
+static_assert(__is_trivially_constructible(__unsafe_unretained id, __unsafe_unretained id&&), "");
+
+static_assert(__is_trivially_constructible(HasStrong, HasStrong), "");
+static_assert(__is_trivially_constructible(HasStrong, HasStrong&&), "");
+static_assert(!__is_trivially_constructible(HasWeak, HasWeak), "");
+static_assert(!__is_trivially_constructible(HasWeak, HasWeak&&), "");
+static_assert(__is_trivially_constructible(HasUnsafeUnretained, HasUnsafeUnretained), "");
+static_assert(__is_trivially_constructible(HasUnsafeUnretained, HasUnsafeUnretained&&), "");
 
 // __is_trivially_relocatable
-TRAIT_IS_TRUE(__is_trivially_relocatable, __strong id);
-TRAIT_IS_FALSE(__is_trivially_relocatable, __weak id);
-TRAIT_IS_TRUE(__is_trivially_relocatable, __autoreleasing id);
-TRAIT_IS_TRUE(__is_trivially_relocatable, __unsafe_unretained id);
-TRAIT_IS_TRUE(__is_trivially_relocatable, HasStrong);
-TRAIT_IS_FALSE(__is_trivially_relocatable, HasWeak);
-TRAIT_IS_TRUE(__is_trivially_relocatable, HasUnsafeUnretained);
+static_assert(__is_trivially_relocatable(__strong id), "");
+static_assert(!__is_trivially_relocatable(__weak id), "");
+static_assert(__is_trivially_relocatable(__autoreleasing id), "");
+static_assert(__is_trivially_relocatable(__unsafe_unretained id), "");
+static_assert(__is_trivially_relocatable(HasStrong), "");
+static_assert(!__is_trivially_relocatable(HasWeak), "");
+static_assert(__is_trivially_relocatable(HasUnsafeUnretained), "");

>From f860bb65f8fe82aa1d5b727abb20de1cb8164b7e Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 29 Jun 2024 15:35:23 +0300
Subject: [PATCH 3/5] Prevent the warning from being issued in `__has_builtin`

---
 clang/include/clang/Lex/Preprocessor.h | 3 +++
 clang/lib/Lex/PPMacroExpansion.cpp     | 2 ++
 clang/lib/Lex/Preprocessor.cpp         | 2 +-
 3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 9d8a1aae23df3..810059cd47d03 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1107,6 +1107,9 @@ class Preprocessor {
   /// Whether tokens are being skipped until the through header is seen.
   bool SkippingUntilPCHThroughHeader = false;
 
+  /// Whether we're evaluating __has_builtin().
+  bool EvaluatingHasBuiltinMacro = false;
+
   /// \{
   /// Cache of macro expanders to reduce malloc traffic.
   enum { TokenLexerCacheSize = 8 };
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index f085b94371644..9b9d06c738aa8 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1673,6 +1673,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
         return II && HasExtension(*this, II->getName());
       });
   } else if (II == Ident__has_builtin) {
+    EvaluatingHasBuiltinMacro = true;
     EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false,
       [this](Token &Tok, bool &HasLexedNextToken) -> int {
         IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
@@ -1734,6 +1735,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
               .Default(false);
         }
       });
+    EvaluatingHasBuiltinMacro = false;
   } else if (II == Ident__has_constexpr_builtin) {
     EvaluateFeatureLikeBuiltinMacro(
         OS, Tok, II, *this, false,
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 7fb1e4db3b87e..e734183fbdbcb 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -837,7 +837,7 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
     II.setIsFutureCompatKeyword(false);
   }
 
-  if (II.isReusableBuiltinName() && !isNextPPTokenLParen()) {
+  if (II.isReusableBuiltinName() && !isNextPPTokenLParen() && !EvaluatingHasBuiltinMacro) {
     Identifier.setKind(tok::identifier);
     Diag(Identifier, diag::warn_deprecated_builtin_replacement) << II.getName();
   }

>From 270ed0eb0b82e9859c3e56f6e4ca7dac1d7b4eb7 Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 29 Jun 2024 18:47:09 +0300
Subject: [PATCH 4/5] Add a comment and a release note

---
 clang/docs/ReleaseNotes.rst    | 4 ++++
 clang/lib/Lex/Preprocessor.cpp | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0f958d213172a..7f026b6f9c953 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -132,6 +132,10 @@ Clang Frontend Potentially Breaking Changes
     $ clang --target=<your target triple> -print-target-triple
     <the normalized target triple>
 
+- Clang now issues a deprecation warning when an identifier of a builtin is used
+  for something else than invoking the builtin, e.g. ``struct __is_pointer``.
+  This affects libstdc++ prior to 14.2, and libc++ prior to 3.5.
+
 - The ``hasTypeLoc`` AST matcher will no longer match a ``classTemplateSpecializationDecl``;
   existing uses should switch to ``templateArgumentLoc`` or ``hasAnyTemplateArgumentLoc`` instead.
 
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index e734183fbdbcb..eccc1208c6ee0 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -837,6 +837,10 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
     II.setIsFutureCompatKeyword(false);
   }
 
+  // Standard libraries used to declare structs with the same (reserved) names
+  // as our builtins for type traits, e.g. __is_pod. This is deprecated, and
+  // we warn when our builtin identifiers are used for something else than
+  // invocation. Notable exception is __has_builtin macro.
   if (II.isReusableBuiltinName() && !isNextPPTokenLParen() && !EvaluatingHasBuiltinMacro) {
     Identifier.setKind(tok::identifier);
     Diag(Identifier, diag::warn_deprecated_builtin_replacement) << II.getName();

>From 6e222443ba61ece890230d5d1fa761bddd9058ce Mon Sep 17 00:00:00 2001
From: Vlad Serebrennikov <serebrennikov.vladislav at gmail.com>
Date: Sat, 29 Jun 2024 18:49:20 +0300
Subject: [PATCH 5/5] Apply formatting suggestions

---
 clang/lib/Lex/Preprocessor.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index eccc1208c6ee0..8b32493b4f533 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -841,7 +841,8 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
   // as our builtins for type traits, e.g. __is_pod. This is deprecated, and
   // we warn when our builtin identifiers are used for something else than
   // invocation. Notable exception is __has_builtin macro.
-  if (II.isReusableBuiltinName() && !isNextPPTokenLParen() && !EvaluatingHasBuiltinMacro) {
+  if (II.isReusableBuiltinName() && !isNextPPTokenLParen() &&
+      !EvaluatingHasBuiltinMacro) {
     Identifier.setKind(tok::identifier);
     Diag(Identifier, diag::warn_deprecated_builtin_replacement) << II.getName();
   }



More information about the cfe-commits mailing list