[clang] [Clang] Support for LibBuiltins with placeholder return types (PR #101702)

Mital Ashok via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 2 09:19:31 PDT 2024


https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/101702

>From 4a7bda13cf7804db1ffce81d3aac77a192585e07 Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Fri, 2 Aug 2024 16:27:54 +0100
Subject: [PATCH] [Clang] Support for LibBuiltins with placeholder return types

---
 clang/docs/ReleaseNotes.rst                   |  1 +
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |  2 +-
 clang/lib/Sema/SemaType.cpp                   |  4 +-
 .../builtin-std-move-placeholder-return.cpp   | 62 +++++++++++++++++++
 clang/test/SemaCXX/builtin-std-move.cpp       |  4 ++
 5 files changed, 71 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/SemaCXX/builtin-std-move-placeholder-return.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 25f5bd37bbe94..46adb5bea2b57 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -173,6 +173,7 @@ Bug Fixes to C++ Support
 - Clang now correctly parses potentially declarative nested-name-specifiers in pointer-to-member declarators.
 - Fix a crash when checking the initialzier of an object that was initialized
   with a string literal. (#GH82167)
+- Clang can now use the definition of ``std::forward_like`` in libstdc++ 14.1 and 14.2. (#GH101614)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f93cd113988ae..2f9b537814661 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4895,7 +4895,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
   // Never implicitly instantiate a builtin; we don't actually need a function
   // body.
   if (Function->getBuiltinID() && TSK == TSK_ImplicitInstantiation &&
-      !DefinitionRequired)
+      !DefinitionRequired && !Function->getReturnType()->isUndeducedType())
     return;
 
   // Don't instantiate a definition if we already have one.
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 6fa39cdccef2b..5a2dfc3228690 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9468,7 +9468,9 @@ QualType Sema::getDecltypeForExpr(Expr *E) {
 }
 
 QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) {
-  assert(!E->hasPlaceholderType() && "unexpected placeholder");
+  assert((!E->hasPlaceholderType() ||
+          E->getType()->isSpecificBuiltinType(BuiltinType::Kind::BuiltinFn)) &&
+         "unexpected placeholder");
 
   if (AsUnevaluated && CodeSynthesisContexts.empty() &&
       !E->isInstantiationDependent() && E->HasSideEffects(Context, false)) {
diff --git a/clang/test/SemaCXX/builtin-std-move-placeholder-return.cpp b/clang/test/SemaCXX/builtin-std-move-placeholder-return.cpp
new file mode 100644
index 0000000000000..62446fdf4f3db
--- /dev/null
+++ b/clang/test/SemaCXX/builtin-std-move-placeholder-return.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -std=c++23 -verify %s -DPLACEHOLDER="decltype(auto)"
+// RUN: %clang_cc1 -std=c++23 -verify %s -DPLACEHOLDER="auto&&"
+// RUN: %clang_cc1 -std=c++23 -verify %s -DPLACEHOLDER="True decltype(auto)"
+
+// expected-no-diagnostics
+
+template<class T>
+concept True = true;
+
+namespace std {
+  template<class T>
+  constexpr PLACEHOLDER move(T&& t) noexcept {
+    return static_cast<__remove_reference_t(T)&&>(t);
+  }
+  constexpr PLACEHOLDER move_if_noexcept(auto& t) noexcept {
+    return static_cast<__remove_reference_t(decltype(t))&&>(t);
+  }
+  template<class T, class U>
+  constexpr PLACEHOLDER forward_like(U&& x) noexcept {
+    if constexpr (__is_const(__remove_reference_t(T))) {
+      using copy_const = const __remove_reference_t(U);
+      if constexpr (__is_rvalue_reference(T&&)) {
+        using V = __remove_reference_t(copy_const)&&;
+        return static_cast<V>(x);
+      } else {
+        using V = copy_const&;
+        return static_cast<V>(x);
+      }
+    } else {
+      using copy_const = __remove_reference_t(U);
+      if constexpr (__is_rvalue_reference(T&&)) {
+        using V = __remove_reference_t(copy_const)&&;
+        return static_cast<V>(x);
+      } else {
+        using V = copy_const&;
+        return static_cast<V>(x);
+      }
+    }
+  }
+}
+
+namespace GH101614 {
+int i;
+static_assert(__is_same(decltype(std::move(i)), int&&));
+static_assert(__is_same(decltype(std::move_if_noexcept(i)), int&&));
+static_assert(__is_same(decltype(std::forward_like<char>(i)), int&&));
+static_assert(__is_same(decltype(std::forward_like<char&>(i)), int&));
+
+constexpr bool is_i(int&& x) { return &x == &i; }
+void is_i(int&) = delete;
+void is_i(auto&&) = delete;
+
+static_assert(is_i(std::move(i)));
+static_assert(is_i(std::move_if_noexcept(i)));
+static_assert(is_i(std::forward_like<char>(i)));
+static_assert(&std::forward_like<char&>(i) == &i);
+
+// These types are incorrect, but make sure the types as declared are used
+static_assert(__is_same(decltype(std::move<int(&)()>), auto(int(&)()) noexcept -> int(&)()));
+static_assert(__is_same(decltype(std::move_if_noexcept<int(&)()>), auto(int(&)()) noexcept -> int(&)()));
+static_assert(__is_same(decltype(std::forward_like<int, int(&)()>), auto(int(&)()) noexcept -> int(&)()));
+} // namespace GH101614
diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index a2ae21986308a..da85703c5d58e 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -172,3 +172,7 @@ namespace std {
   template<typename T> int &move(T);
 }
 int bad_signature = std::move(0); // expected-error {{unsupported signature for 'std::move<int>'}}
+
+namespace GH101690 {
+decltype(std::move_if_noexcept<int>)* p = nullptr;
+}



More information about the cfe-commits mailing list