royjacobson created this revision.
Herald added a project: All.
royjacobson requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Some compiler provided type traits like __has_trivial_constructor have been 
documented
as deprecated for quite some time.
Still, some people apparently still use them, even though mixing them with 
concepts
and with deleted functions leads to weird results. There's also disagreement 
about some
edge cases between GCC (which Clang claims to follow) and MSVC.

This patch adds deprecation warnings for the usage of those builtins, except 
for __has_trivial_destructor
which doesn't have a GCC alternative.

I made the warning on by default, so I had to silence it for some tests but 
it's not too many.

Some (decade old) history of issues with those builtins:
https://github.com/llvm/llvm-project/issues/18187
https://github.com/llvm/llvm-project/issues/18559
https://github.com/llvm/llvm-project/issues/22161
https://github.com/llvm/llvm-project/issues/33063

The abseil usage of them that triggered me to add this warning:
https://github.com/abseil/abseil-cpp/issues/1201

Weird interaction of those builtins with C++20's conditionally trivial special 
member functions:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106085


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D129170

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticGroups.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExprCXX.cpp
  clang/test/CXX/dcl.decl/dcl.init/p5.cpp
  clang/test/CXX/drs/dr18xx.cpp
  clang/test/CXX/drs/dr21xx.cpp
  clang/test/CXX/special/class.copy/p12-0x.cpp
  clang/test/CXX/special/class.copy/p25-0x.cpp
  clang/test/CXX/special/class.ctor/p5-0x.cpp
  clang/test/Modules/cxx-decls.cpp
  clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
  clang/test/SemaCXX/cxx11-crashes.cpp
  clang/test/SemaCXX/deprecated-builtins.cpp
  clang/test/SemaCXX/sizeless-1.cpp
  clang/test/SemaCXX/trivial-constructor.cpp
  clang/test/SemaCXX/trivial-destructor.cpp
  clang/test/SemaCXX/type-traits.cpp
  clang/test/SemaObjCXX/arc-type-traits.mm
  clang/test/SemaObjCXX/objc-weak-type-traits.mm

Index: clang/test/SemaObjCXX/objc-weak-type-traits.mm
===================================================================
--- clang/test/SemaObjCXX/objc-weak-type-traits.mm
+++ clang/test/SemaObjCXX/objc-weak-type-traits.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-weak -fobjc-runtime-has-weak -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-weak -fobjc-runtime-has-weak -verify -std=c++11 %s -Wno-deprecated-has-builtins
 // expected-no-diagnostics
 
 // Check the results of the various type-trait query functions on
Index: clang/test/SemaObjCXX/arc-type-traits.mm
===================================================================
--- clang/test/SemaObjCXX/arc-type-traits.mm
+++ clang/test/SemaObjCXX/arc-type-traits.mm
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -fobjc-arc -fobjc-runtime-has-weak -verify -std=c++11 %s -Wno-deprecated-has-builtins
 // expected-no-diagnostics
 
 // Check the results of the various type-trait query functions on
Index: clang/test/SemaCXX/type-traits.cpp
===================================================================
--- clang/test/SemaCXX/type-traits.cpp
+++ clang/test/SemaCXX/type-traits.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fms-extensions -Wno-microsoft %s
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -Wno-deprecated-has-builtins -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -Wno-deprecated-has-builtins -fms-extensions -Wno-microsoft %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -Wno-deprecated-has-builtins -fms-extensions -Wno-microsoft %s
 
 #define T(b) (b) ? 1 : -1
 #define F(b) (b) ? -1 : 1
Index: clang/test/SemaCXX/trivial-destructor.cpp
===================================================================
--- clang/test/SemaCXX/trivial-destructor.cpp
+++ clang/test/SemaCXX/trivial-destructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-deprecated-has-builtins
 // expected-no-diagnostics
 struct T1 {
 };
Index: clang/test/SemaCXX/trivial-constructor.cpp
===================================================================
--- clang/test/SemaCXX/trivial-constructor.cpp
+++ clang/test/SemaCXX/trivial-constructor.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-deprecated-has-builtins
 // expected-no-diagnostics
 struct T1 {
 };
Index: clang/test/SemaCXX/sizeless-1.cpp
===================================================================
--- clang/test/SemaCXX/sizeless-1.cpp
+++ clang/test/SemaCXX/sizeless-1.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wno-unused-but-set-variable -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++98 %s
-// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wno-unused-but-set-variable -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++11 %s
-// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wno-unused-but-set-variable -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++17 %s
-// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wno-unused-but-set-variable -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++17 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wno-deprecated-has-builtins -Wno-unused-but-set-variable -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++11 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wno-deprecated-has-builtins -Wno-unused-but-set-variable -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=c++17 %s
+// RUN: %clang_cc1 -fcxx-exceptions -fsyntax-only -verify -W -Wall -Wno-deprecated-has-builtins -Wno-unused-but-set-variable -Wrange-loop-analysis -triple arm64-linux-gnu -target-feature +sve -std=gnu++17 %s
 
 namespace std {
 struct type_info;
Index: clang/test/SemaCXX/deprecated-builtins.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/deprecated-builtins.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+struct A {};
+
+void f() {
+    bool a;
+
+    a = __has_nothrow_assign(A);  // expected-warning-re {{the __has_nothrow_assign {{.*}} Use __is_nothrow_assignable}}
+    a = __has_nothrow_move_assign(A);  // expected-warning-re {{the __has_nothrow_move_assign {{.*}} Use __is_nothrow_assignable}}
+    a = __has_nothrow_copy(A);  // expected-warning-re {{the __has_nothrow_copy {{.*}} Use __is_nothrow_constructible}}
+    a = __has_nothrow_constructor(A);  // expected-warning-re {{the __has_nothrow_constructor {{.*}} Use __is_nothrow_constructible}}
+    a = __has_trivial_assign(A);  // expected-warning-re {{the __has_trivial_assign {{.*}} Use __is_trivially_assignable}}
+    a = __has_trivial_move_assign(A);  // expected-warning-re {{the __has_trivial_move_assign {{.*}} Use __is_trivially_assignable}}
+    a = __has_trivial_copy(A);  // expected-warning-re {{the __has_trivial_copy {{.*}} Use __is_trivially_constructible}}
+    a = __has_trivial_constructor(A);  // expected-warning-re {{the __has_trivial_constructor {{.*}} Use __is_trivially_constructible}}
+    a = __has_trivial_move_constructor(A);  // expected-warning-re {{the __has_trivial_move_constructor {{.*}} Use __is_trivially_constructible}}
+    a = __has_trivial_destructor(A);
+
+}
Index: clang/test/SemaCXX/cxx11-crashes.cpp
===================================================================
--- clang/test/SemaCXX/cxx11-crashes.cpp
+++ clang/test/SemaCXX/cxx11-crashes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-has-builtins
 
 // rdar://12240916 stack overflow.
 namespace rdar12240916 {
Index: clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
===================================================================
--- clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
+++ clang/test/SemaCXX/cxx0x-defaulted-functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fcxx-exceptions -Wno-deprecated-has-builtins %s
 
 void fn() = default; // expected-error {{only special member}}
 struct foo {
Index: clang/test/Modules/cxx-decls.cpp
===================================================================
--- clang/test/Modules/cxx-decls.cpp
+++ clang/test/Modules/cxx-decls.cpp
@@ -1,6 +1,6 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
-// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs %s -ast-dump -ast-dump-filter merge -std=c++11 | FileCheck %s
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -Wno-deprecated-has-builtins -I %S/Inputs %s -verify -std=c++11
+// RUN: %clang_cc1 -x objective-c++ -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -Wno-deprecated-has-builtins -I %S/Inputs %s -ast-dump -ast-dump-filter merge -std=c++11 | FileCheck %s
 
 // expected-no-diagnostics
 
Index: clang/test/CXX/special/class.ctor/p5-0x.cpp
===================================================================
--- clang/test/CXX/special/class.ctor/p5-0x.cpp
+++ clang/test/CXX/special/class.ctor/p5-0x.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 -Wno-deprecated-has-builtins -Wno-defaulted-function-deleted
 
 struct DefaultedDefCtor1 {};
 struct DefaultedDefCtor2 { DefaultedDefCtor2() = default; };
Index: clang/test/CXX/special/class.copy/p25-0x.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p25-0x.cpp
+++ clang/test/CXX/special/class.copy/p25-0x.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -verify %s
-// RUN: %clang_cc1 -std=c++11 -verify %s -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-has-builtins
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-has-builtins -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14
 
 // expected-no-diagnostics
 
Index: clang/test/CXX/special/class.copy/p12-0x.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p12-0x.cpp
+++ clang/test/CXX/special/class.copy/p12-0x.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-defaulted-function-deleted
-// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-defaulted-function-deleted -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-has-builtins -Wno-defaulted-function-deleted
+// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-deprecated-has-builtins -Wno-defaulted-function-deleted -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14
 
 // expected-no-diagnostics
 
Index: clang/test/CXX/drs/dr21xx.cpp
===================================================================
--- clang/test/CXX/drs/dr21xx.cpp
+++ clang/test/CXX/drs/dr21xx.cpp
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -Wno-deprecated-has-builtins -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -Wno-deprecated-has-builtins -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -Wno-deprecated-has-builtins -fcxx-exceptions -pedantic-errors
 
 #if __cplusplus < 201103L
 // expected-error@+1 {{variadic macro}}
Index: clang/test/CXX/drs/dr18xx.cpp
===================================================================
--- clang/test/CXX/drs/dr18xx.cpp
+++ clang/test/CXX/drs/dr18xx.cpp
@@ -1,8 +1,8 @@
 // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
-// RUN: %clang_cc1 -std=c++2a -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -Wno-deprecated-has-builtins -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -Wno-deprecated-has-builtins -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify -fexceptions -Wno-deprecated-has-builtins -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++2a -triple x86_64-unknown-unknown %s -verify -fexceptions -Wno-deprecated-has-builtins -fcxx-exceptions -pedantic-errors
 
 #if __cplusplus < 201103L
 // expected-error@+1 {{variadic macro}}
Index: clang/test/CXX/dcl.decl/dcl.init/p5.cpp
===================================================================
--- clang/test/CXX/dcl.decl/dcl.init/p5.cpp
+++ clang/test/CXX/dcl.decl/dcl.init/p5.cpp
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-deprecated-has-builtins -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-deprecated-has-builtins %s
 
 //   A program that calls for default-initialization or value-initialization of
 //   an entity of reference type is illformed. If T is a cv-qualified type, the
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -5394,6 +5394,54 @@
   return false;
 }
 
+namespace {
+void IssueBuiltinDeprecationWarningIfNeeded(Sema& S, TypeTrait Kind,
+                                            SourceLocation KWLoc) {
+  if (!S.getLangOpts().CPlusPlus11)
+    return;
+
+  TypeTrait Replacement;
+  switch (Kind) {
+    case UTT_HasNothrowAssign:
+      Replacement = BTT_IsNothrowAssignable;
+      break;
+    case UTT_HasNothrowMoveAssign:
+      Replacement = BTT_IsNothrowAssignable;
+      break;
+    case UTT_HasNothrowCopy:
+      Replacement = TT_IsNothrowConstructible;
+      break;
+    case UTT_HasNothrowConstructor:
+      Replacement = TT_IsNothrowConstructible;
+      break;
+    case UTT_HasTrivialAssign:
+      Replacement = BTT_IsTriviallyAssignable;
+      break;
+    case UTT_HasTrivialMoveAssign:
+      Replacement = BTT_IsTriviallyAssignable;
+      break;
+    case UTT_HasTrivialCopy:
+      Replacement = TT_IsTriviallyConstructible;
+      break;
+    case UTT_HasTrivialDefaultConstructor:
+      Replacement = TT_IsTriviallyConstructible;
+      break;
+    case UTT_HasTrivialMoveConstructor:
+      Replacement = TT_IsTriviallyConstructible;
+      break;
+    // FIXME: GCC don't implement __is_trivially_destructible: Warning for this
+    //   might be too noisy for now.
+    // case UTT_HasTrivialDestructor:
+    //   Replacement = UTT_IsTriviallyDestructible;
+    //   break;
+    default:
+      return;
+  }
+  S.Diag(KWLoc, diag::warn_deprecated_has_builtins)
+    << getTraitSpelling(Kind) << getTraitSpelling(Replacement);
+}
+}
+
 ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc,
                                 ArrayRef<TypeSourceInfo *> Args,
                                 SourceLocation RParenLoc) {
@@ -5403,6 +5451,8 @@
                                *this, Kind, KWLoc, Args[0]->getType()))
     return ExprError();
 
+  IssueBuiltinDeprecationWarningIfNeeded(*this, Kind, KWLoc);
+
   bool Dependent = false;
   for (unsigned I = 0, N = Args.size(); I != N; ++I) {
     if (Args[I]->getType()->isDependentType()) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5557,6 +5557,9 @@
 def warn_unavailable_def : Warning<
   "implementing unavailable method">,
   InGroup<DeprecatedImplementations>, DefaultIgnore;
+def warn_deprecated_has_builtins : Warning<
+  "the %0 compiler builtin is deprecated from C++11 onwards. Use %1 instead.">,
+  InGroup<DeprecatedHasBuiltins>;
 def err_unavailable : Error<"%0 is unavailable">;
 def err_property_method_unavailable :
     Error<"property access is using %0 method which is unavailable">;
Index: clang/include/clang/Basic/DiagnosticGroups.td
===================================================================
--- clang/include/clang/Basic/DiagnosticGroups.td
+++ clang/include/clang/Basic/DiagnosticGroups.td
@@ -187,6 +187,7 @@
 def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
 def DeprecatedDynamicExceptionSpec
     : DiagGroup<"deprecated-dynamic-exception-spec">;
+def DeprecatedHasBuiltins : DiagGroup<"deprecated-has-builtins">;
 def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
 def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
 def DeprecatedRegister : DiagGroup<"deprecated-register">;
@@ -209,6 +210,7 @@
                                           DeprecatedEnumCompareConditional,
                                           DeprecatedEnumEnumConversion,
                                           DeprecatedEnumFloatConversion,
+                                          DeprecatedHasBuiltins,
                                           DeprecatedIncrementBool,
                                           DeprecatedPragma,
                                           DeprecatedRegister,
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -302,6 +302,10 @@
   - ASAN_OPTIONS=detect_stack_use_after_return=1 (only on Linux).
   - MSAN_OPTIONS=poison_in_dtor=1.
 
+- Some type traits builtins like ``__has_trivial_assign`` have been documented
+  as deprecated for a while, because their semantics don't mix well with post-C++11 type
+  traits. Clang now emits deprecation warnings for them under the flag ``-Wdeprecated-has-builtins``.
+
 New Compiler Flags
 ------------------
 - Added the ``-fno-knr-functions`` flag to allow users to opt into the C2x
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to