[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-12-02 Thread Nico Weber via cfe-commits

nico wrote:

I reverted this in e05fffbbc54d201a60e55e8c051bad81eaebd69a for now, per 
Discord.

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-12-02 Thread Nico Weber via cfe-commits

nico wrote:

Here's another snippet that builds fine before this patch but not after it:

```
#include 

template 
class Foo;

struct Baz {
  Baz() = default;

#if 0
  Baz(Foo foo) {}
#else
  template 
requires(std::is_convertible_v>)
  explicit Baz(T foo) {}
#endif
};

struct Quux {
  mutable Baz baz;
};
```

```
# libc++ built as described in libcxx/docs/VendorDocumentation.rst,
# but with -DCMAKE_INSTALL_PREFIX=$PWD/install-libcxx added to cmake invocation
# ninja -C build cxx cxxabi unwind
# ninja -C build install-cxx install-cxxabi install-unwind

out/gn/bin/clang -c repro.cc -std=c++20 -nostdinc++ -isystem 
install-libcxx/include/c++/v1 
```

Before, this built fine. After, it yields

```
% out/gn/bin/clang -c repro.cc -std=c++20 -nostdinc++ -isystem 
install-libcxx/include/c++/v1 
In file included from repro.cc:1:
In file included from install-libcxx/include/c++/v1/type_traits:491:
install-libcxx/include/c++/v1/__type_traits/is_convertible.h:26:96: error: 
implicit instantiation of undefined template 'Foo'
   26 | _LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_convertible_v = 
__is_convertible(_From, _To);
  | 
   ^
repro.cc:13:19: note: in instantiation of variable template specialization 
'std::is_convertible_v>' requested here
   13 | requires(std::is_convertible_v>)
  |   ^
repro.cc:13:14: note: while substituting template arguments into constraint 
expression here
   13 | requires(std::is_convertible_v>)
  |  ^~
repro.cc:6:34: note: while checking constraint satisfaction for template 
'Baz' required here
6 | struct __attribute__((lockable)) Baz {
  |  ^~~
repro.cc:6:34: note: while substituting deduced template arguments into 
function template 'Baz' [with T = Baz]
repro.cc:18:8: note: while declaring the implicit copy constructor for 'Quux'
   18 | struct Quux {
  |^
repro.cc:4:7: note: template is declared here
4 | class Foo;
  |   ^
1 error generated.
```

The snippet is a bit weird! The motivation is that it wants to say 
`Baz(Foo foo) {}`, but `Foo` is forward-declared, so it uses that 
template hack, and everyone who wants to call that ctor has to make sure to 
include a definition of `Foo<>`.

This worked before this change, but not after. Was that behavior change 
intentional? (The repro only works if the `mutable` is present somehow, which 
suggests that this isn't intentional.)

Maybe this is also what's causing the libc++-built-as-module diag mentioned 
above?

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-12-02 Thread Nico Weber via cfe-commits

nico wrote:

This breaks building the libc++ module in the chromium build for me:

```
../../../../llvm-project/out/gn/bin/clang++ -MD -MF 
clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/std/module.pcm.d
 -D__ARM_NEON__=1 -DCR_XCODE_BUILD=17B100 
-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE 
-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS 
-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS -D_LIBCPP_INSTRUMENTED_WITH_ASAN=0 
-DCR_LIBCXX_REVISION=91c45fc28459e814889633be985b698c5e8050b4 -DNDEBUG 
-DNVALGRIND -DDYNAMIC_ANNOTATIONS_ENABLED=0 -D_LIBCPP_BUILDING_LIBRARY -I../.. 
-Iclang_arm64_for_rust_host_build_tools/gen -fno-delete-null-pointer-checks 
-fno-strict-overflow -fno-ident -fno-math-errno -fno-strict-aliasing 
-fstack-protector -fcolor-diagnostics -fmerge-all-constants 
-fno-sized-deallocation -fcrash-diagnostics-dir=../clang-crashreports -mllvm 
-instcombine-lower-dbg-declare=0 -mllvm -split-threshold-for-reg-with-hint=0 
-ffp-contract=off -fcomplete-member-pointers --target=arm64-apple-macos 
-mno-outline -Wno-builtin-macro-redefined -D__DATE__= -D__TIME__= 
-D__TIMESTAMP__= -ffile-compilation-dir=. -no-canonical-prefixes -Xclang 
-fmodule-file-home-is-cwd -Xclang -fmodules-cache-path=/not_exist_dummy_dir 
--warning-suppression-mappings=../../build/config/warning_suppression.txt 
-ftrivial-auto-var-init=pattern -O2 -fno-omit-frame-pointer -g0 -isysroot 
../../../../../../../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.1.sdk
 -mmacos-version-min=12.0 -fsanitize=array-bounds -fsanitize-trap=array-bounds 
-fvisibility=hidden -Wheader-hygiene -Wstring-conversion 
-Wtautological-overlap-compare -fstrict-aliasing -Wundef -fPIC -Wall 
-Wno-unused-variable -Wno-c++11-narrowing -Wno-unused-but-set-variable 
-Wunguarded-availability -Wno-missing-field-initializers -Wno-unused-parameter 
-Wno-psabi -Wloop-analysis -Wno-unneeded-internal-declaration 
-Wno-cast-function-type -Wno-thread-safety-reference-return 
-Wno-nontrivial-memcall -Wno-uninitialized-const-pointer 
-Wexit-time-destructors -Werror -Wno-exit-time-destructors -std=c++20 
-Wno-trigraphs -fno-exceptions -fno-rtti -nostdinc++ 
-isystemgen/third_party/libc++/src/include 
-isystem../../third_party/libc++abi/src/include -fvisibility-inlines-hidden 
-Wno-invalid-offsetof -Wenum-compare-conditional -Wno-nullability-completeness 
-fbuiltin-module-map 
-fmodule-map-file=gen/third_party/libc++/src/include/module.modulemap 
-fmodule-map-file=../../../../../../../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.1.sdk/usr/include/DarwinBasic.modulemap
 
-fmodule-map-file=../../../../../../../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.1.sdk/usr/include/DarwinFoundation1.modulemap
 
-fmodule-map-file=../../../../../../../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.1.sdk/usr/include/DarwinFoundation2.modulemap
 
-fmodule-map-file=../../../../../../../Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.1.sdk/usr/include/DarwinFoundation3.modulemap
 
-fmodule-file=_AvailabilityInternal=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_AvailabilityInternal/DarwinFoundation1.pcm
 
-fmodule-file=_Builtin_float=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_Builtin_float/module.pcm
 
-fmodule-file=_Builtin_inttypes=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_Builtin_inttypes/module.pcm
 
-fmodule-file=_Builtin_limits=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_Builtin_limits/module.pcm
 
-fmodule-file=_Builtin_stdalign=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_Builtin_stdalign/module.pcm
 
-fmodule-file=_Builtin_stdarg=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_Builtin_stdarg/module.pcm
 
-fmodule-file=_Builtin_stddef=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_Builtin_stddef/module.pcm
 
-fmodule-file=_Builtin_stdint=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_Builtin_stdint/module.pcm
 
-fmodule-file=_DarwinFoundation1=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_DarwinFoundation1/DarwinFoundation1.pcm
 
-fmodule-file=_DarwinFoundation2=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_DarwinFoundation2/DarwinFoundation2.pcm
 
-fmodule-file=_DarwinFoundation3=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/_DarwinFoundation3/DarwinFoundation3.pcm
 
-fmodule-file=std_core=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/std_core/module.pcm
 
-fmodule-file=std_ctype_h=clang_arm64_for_rust_host_build_tools/obj/buildtools/third_party/libc++/std_ctype_h/module.pcm
 
-fmodule-file=std_errno_h=clang_arm64

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-12-01 Thread Nikolas Klauser via cfe-commits

philnik777 wrote:

Landing for now, since I don't think there are big concerns anymore and I'd 
like to avoid merge conflicts. @shafik @AaronBallman if you have any more 
comments I'm happy to address them post-commit.

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-12-01 Thread LLVM Continuous Integration via cfe-commits

llvm-ci wrote:

LLVM Buildbot has detected a new failure on builder `clang-m68k-linux-cross` 
running on `suse-gary-m68k-cross` while building `clang,libcxx` at step 5 
"ninja check 1".

Full details are available at: 
https://lab.llvm.org/buildbot/#/builders/27/builds/19672


Here is the relevant piece of the build log for the reference

```
Step 5 (ninja check 1) failure: stage 1 checked (failure)
...
[51/406] Building CXX object 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/ClangTidyDiagnosticConsumerTest.cpp.o
[52/406] Building CXX object 
tools/clang/tools/extra/unittests/clang-change-namespace/CMakeFiles/ClangChangeNamespaceTests.dir/ChangeNamespaceTests.cpp.o
[53/406] Building CXX object 
tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/DataflowAnalysisContextTest.cpp.o
[54/406] Building CXX object 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/TransformerClangTidyCheckTest.cpp.o
[55/406] Building CXX object 
tools/clang/tools/extra/include-cleaner/unittests/CMakeFiles/ClangIncludeCleanerTests.dir/FindHeadersTest.cpp.o
[56/406] Building CXX object 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/IncludeInserterTest.cpp.o
[57/406] Building CXX object 
tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/IntervalPartitionTest.cpp.o
[58/406] Building CXX object 
tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/CFGTest.cpp.o
[59/406] Building CXX object 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/AddConstTest.cpp.o
[60/406] Building CXX object 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/OverlappingReplacementsTest.cpp.o
FAILED: 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/OverlappingReplacementsTest.cpp.o
 
/usr/bin/c++ -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -D_DEBUG 
-D_GLIBCXX_ASSERTIONS -D_GLIBCXX_USE_CXX11_ABI=1 -D_GNU_SOURCE 
-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/tools/extra/unittests/clang-tidy
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/unittests/clang-tidy
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/unittests/clang-tidy/../../include-cleaner/include
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang/include
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/tools/clang/include
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/stage1/include
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/llvm/include
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/clang-tidy
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googletest/include
 
-I/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/third-party/unittest/googlemock/include
 -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden 
-Werror=date-time -Wall -Wextra -Wno-unused-parameter -Wwrite-strings 
-Wcast-qual -Wno-missing-field-initializers -pedantic -Wno-long-long 
-Wimplicit-fallthrough -Wno-uninitialized -Wno-nonnull -Wno-class-memaccess 
-Wno-dangling-reference -Wno-redundant-move -Wno-pessimizing-move 
-Wno-array-bounds -Wno-stringop-overread -Wno-noexcept-type 
-Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment 
-Wno-misleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color 
-ffunction-sections -fdata-sections -fno-common -Woverloaded-virtual -O3 
-DNDEBUG -std=c++17  -Wno-variadic-macros -fno-exceptions -funwind-tables 
-fno-rtti -UNDEBUG -Wno-suggest-override -MD -MT 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/OverlappingReplacementsTest.cpp.o
 -MF 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/OverlappingReplacementsTest.cpp.o.d
 -o 
tools/clang/tools/extra/unittests/clang-tidy/CMakeFiles/ClangTidyTests.dir/OverlappingReplacementsTest.cpp.o
 -c 
/var/lib/buildbot/workers/suse-gary-m68k-cross/clang-m68k-linux-cross/llvm/clang-tools-extra/unittests/clang-tidy/OverlappingReplacementsTest.cpp
c++: fatal error: Killed signal terminated program cc1plus
compilation terminated.
[61/406] Building CXX object 
tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/ASTTests.cpp.o
[62/406] Building CXX object 
tools/clang/unittests/CMakeFiles/AllClangUnitTests.dir/Analysis/FlowSensitive/CachedConstAccessorsLatticeTest.cpp.o
[63/406] Building CXX object 
tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/FormatTests.cpp.o
[64/406] Building CXX object 
tools/clang/tools/extra/clangd/unittests/CMakeFiles/ClangdTests.dir/FeatureModulesTests.cpp.o
[

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-12-01 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 closed 
https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-11-29 Thread via cfe-commits

https://github.com/huixie90 approved this pull request.

libc++ changes LGTM. Leave the final approval to the clang folks

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-11-28 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 273d0e6149a8326284ec1e385e83c8728c41ff68 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH 1/4] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 353 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 136 +++
 .../include/__type_traits/common_reference.h  |  37 +-
 libcxx/include/module.modulemap   |   1 +
 9 files changed, 642 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..d5282758948cd 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_reference``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQua

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-11-28 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 273d0e6149a8326284ec1e385e83c8728c41ff68 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH 1/3] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 353 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 136 +++
 .../include/__type_traits/common_reference.h  |  37 +-
 libcxx/include/module.modulemap   |   1 +
 9 files changed, 642 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..d5282758948cd 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_reference``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQua

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-11-28 Thread Nikolas Klauser via cfe-commits


@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {

philnik777 wrote:

Currently the names are purely cosmetic in nature except when you have NTTPs 
which rely on a previous type, so I'm not too worried if someone forgets. I 
wanted to auto-generate docs with this at some point, but I didn't get to it 
yet.

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-11-28 Thread Nikolas Klauser via cfe-commits


@@ -3349,6 +3360,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
ElaboratedTypeKeyword Keyword,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())

philnik777 wrote:

What exactly do you want? I'm quoting the standard here, just like everywhere 
else.

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-10-31 Thread Nikolas Klauser via cfe-commits

philnik777 wrote:

@huixie90 Are you happy with landing this now?

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-10-31 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 273d0e6149a8326284ec1e385e83c8728c41ff68 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 353 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 136 +++
 .../include/__type_traits/common_reference.h  |  37 +-
 libcxx/include/module.modulemap   |   1 +
 9 files changed, 642 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..d5282758948cd 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_reference``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualifi

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-07-06 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 273d0e6149a8326284ec1e385e83c8728c41ff68 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 353 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 136 +++
 .../include/__type_traits/common_reference.h  |  37 +-
 libcxx/include/module.modulemap   |   1 +
 9 files changed, 642 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..d5282758948cd 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_reference``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualifi

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-27 Thread Erich Keane via cfe-commits

https://github.com/erichkeane edited 
https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-27 Thread Nikolas Klauser via cfe-commits

philnik777 wrote:

> This seems reasonable to me? I'm not a huge fan of how much is being put into 
> `SemaTemplate.cpp` to support all the builtins though. I'm wondering if we 
> need to split that up in a follow-up and have a `SemaTemplateBuiltins` for 
> all of these to live.

I can take a look at splitting things up in a follow-up. Shouldn't be too 
complicated. I do wonder whether it's worth the split, since it's a relatively 
small amount of code. OTOH it's a very clean split...

> Please let Aaron/others take a poke at this, and make sure there are a few 
> more Libc++ reviewers to make sure you're all in agreement with how this 
> works (I see the convo that is happening).
> 
> Also, should we loop in libstdc++ folks here?

IDK whether they have any thought on this, but certainly doesn't hurt. CC 
@jwakely


https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-27 Thread Nikolas Klauser via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-27 Thread Erich Keane via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-27 Thread Erich Keane via cfe-commits


@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {

erichkeane wrote:

Sorry if I'm being a little dense here... what is going on for the forloop?

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-27 Thread Erich Keane via cfe-commits

https://github.com/erichkeane approved this pull request.

This seems reasonable to me?  I'm not a huge fan of how much is being put into 
`SemaTemplate.cpp` to support all the builtins though.  I'm wondering if we 
need to split that up in a follow-up and have a `SemaTemplateBuiltins` for all 
of these to live.

Please let Aaron/others take a poke at this, and make sure there are a few more 
Libc++ reviewers to make sure you're all in agreement with how this works (I 
see the convo that is happening).

Also, should we loop in libstdc++ folks here?

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-26 Thread A. Jiang via cfe-commits


@@ -17,16 +17,37 @@
 #include <__type_traits/is_reference.h>
 #include <__type_traits/remove_cvref.h>
 #include <__type_traits/remove_reference.h>
+#include <__type_traits/type_identity.h>
 #include <__utility/declval.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
 #endif
 
+#if _LIBCPP_STD_VER >= 20
+
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// common_reference
-#if _LIBCPP_STD_VER >= 20
+template 
+struct common_reference;

frederick-vs-ja wrote:

FYI I've opened #141465 to add `_LIBCPP_NO_SPECIALIZATIONS` to 
`common_reference`. Once the affected test gets fixed, we can also add 
`_LIBCPP_NO_SPECIALIZATIONS` here.

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-25 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-25 Thread A. Jiang via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-25 Thread via cfe-commits

huixie90 wrote:

FWIW, I created patch https://github.com/llvm/llvm-project/pull/141408 to 
implement the libc++ counter part of the missing bit.
So can i request to merge this patch after landing of my patch? the benifits 
are : 
- Avoid behaviour differences between the two branches
- having more test coverage for the new behaviour that the paper introduces

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread Nikolas Klauser via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits

https://github.com/huixie90 edited 
https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits

https://github.com/huixie90 edited 
https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread Nikolas Klauser via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread Nikolas Klauser via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-24 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-05-19 Thread Nikolas Klauser via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-04-13 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-04-11 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 97d6d6918126493fc8c09d9f3af472d701cb2cf9 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 353 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 148 
 .../include/__type_traits/common_reference.h  |  37 +-
 libcxx/include/module.modulemap   |   1 +
 9 files changed, 654 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..d5282758948cd 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_reference``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualif

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-04-11 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 273d0e6149a8326284ec1e385e83c8728c41ff68 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 353 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 136 +++
 .../include/__type_traits/common_reference.h  |  37 +-
 libcxx/include/module.modulemap   |   1 +
 9 files changed, 642 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..d5282758948cd 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_reference``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualifi

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-04-11 Thread Nikolas Klauser via cfe-commits


@@ -145,8 +160,6 @@ struct __common_reference_sub_bullet1<_Tp, _Up> {
 

philnik777 wrote:

I've added one.

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-04-11 Thread Nikolas Klauser via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-04-05 Thread via cfe-commits

https://github.com/huixie90 edited 
https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-04-04 Thread via cfe-commits

https://github.com/huixie90 edited 
https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-31 Thread via cfe-commits


@@ -3231,6 +3241,230 @@ static QualType builtinCommonTypeImpl(Sema &S, 
TemplateName BaseTemplate,
   }
 }
 
+static QualType CopyCV(QualType From, QualType To) {
+  if (From.isConstQualified())
+To.addConst();
+  if (From.isVolatileQualified())
+To.addVolatile();
+  return To;
+}
+
+// COND-RES(X, Y) be decltype(false ? declval()() : 
declval()())
+static QualType CondRes(Sema &S, QualType X, QualType Y, SourceLocation Loc) {
+  EnterExpressionEvaluationContext UnevaluatedContext(
+  S, Sema::ExpressionEvaluationContext::Unevaluated);
+  Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true);
+  Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
+
+  // false
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
+  ExprResult Cond = &CondExpr;
+
+  // declval()()
+  OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(X));
+  ExprResult LHS = &LHSExpr;
+
+  // declval()()
+  OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
+  Expr::getValueKindForType(Y));
+  ExprResult RHS = &RHSExpr;
+
+  ExprValueKind VK = VK_PRValue;
+  ExprObjectKind OK = OK_Ordinary;
+
+  // decltype(false ? declval()() : declval()())
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+
+  if (SFINAE.hasErrorOccurred())
+return QualType();
+  if (VK == VK_LValue)
+return S.BuiltinAddLValueReference(Result, Loc);
+  if (VK == VK_XValue)
+return S.BuiltinAddRValueReference(Result, Loc);
+  return Result;
+}
+
+static QualType CommonRef(Sema &S, QualType A, QualType B, SourceLocation Loc) 
{
+  // Given types A and B, let X be remove_reference_t, let Y be
+  // remove_reference_t, and let COMMON-​REF(A, B) be:
+  assert(A->isReferenceType() && B->isReferenceType() &&
+ "A and B have to be ref qualified for a COMMON-REF");
+  auto X = A.getNonReferenceType();
+  auto Y = B.getNonReferenceType();
+
+  // If A and B are both lvalue reference types, COMMON-REF(A, B) is
+  // COND-RES(COPYCV(X, Y) &, COPYCV(​Y, X) &) if that type exists and is a
+  // reference type.
+  if (A->isLValueReferenceType() && B->isLValueReferenceType()) {
+auto CR = CondRes(S, S.BuiltinAddLValueReference(CopyCV(X, Y), Loc),
+  S.BuiltinAddLValueReference(CopyCV(Y, X), Loc), Loc);
+if (CR.isNull() || !CR->isReferenceType())
+  return QualType();
+return CR;
+  }
+
+  // Otherwise, let C be remove_reference_t&&. If A and B
+  // are both rvalue reference types, C is well-formed, and
+  // is_convertible_v && is_convertible_v is true, then
+  // COMMON-REF(A, B) is C.
+  if (A->isRValueReferenceType() && B->isRValueReferenceType()) {
+auto C = CommonRef(S, S.BuiltinAddLValueReference(X, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (C.isNull())
+  return QualType();
+
+C = C.getNonReferenceType();
+
+if (S.BuiltinIsConvertible(A, C, Loc) && S.BuiltinIsConvertible(B, C, Loc))
+  return S.BuiltinAddRValueReference(C, Loc);
+return QualType();
+  }
+
+  // Otherwise, if A is an lvalue reference and B is an rvalue reference, then
+  // COMMON-REF(A, B) is COMMON-REF(B, A).
+  if (A->isLValueReferenceType() && B->isRValueReferenceType())
+std::swap(A, B);
+
+  // Otherwise, let D be COMMON-REF(const X&, Y&). If A is an rvalue reference
+  // and B is an lvalue reference and D is well-formed and
+  // is_convertible_v is true, then COMMON-REF(A, B) is D.
+  if (A->isRValueReferenceType() && B->isLValueReferenceType()) {
+auto X2 = X;
+X2.addConst();
+auto D = CommonRef(S, S.BuiltinAddLValueReference(X2, Loc),
+   S.BuiltinAddLValueReference(Y, Loc), Loc);
+if (!D.isNull() && S.BuiltinIsConvertible(A, D, Loc))
+  return D;
+return QualType();
+  }
+
+  // Otherwise, COMMON-REF(A, B) is ill-formed.
+  // This is implemented by returning from the individual branches above.
+
+  llvm_unreachable("The above cases should be exhaustive");
+}
+
+static QualType builtinCommonReferenceImpl(Sema &S,
+   TemplateName CommonReference,
+   TemplateName CommonType,
+   SourceLocation TemplateLoc,
+   ArrayRef Ts) {
+  switch (Ts.size()) {
+  // If sizeof...(T) is zero, there shall be no member type.
+  case 0:
+return QualType();
+
+  // Otherwise, if sizeof...(T) is one, let T0 denote the sole type in the
+  // pack T. The member typedef type shall denote the same type as T0.
+  case 1:
+return Ts[0].getAsType();
+
+  // Otherwise, if sizeof...(T) is two, let T1 and T2 denote the two types in
+  // the pack T. Then
+  case 2: {
+auto T1 = Ts[0].getAsType();
+auto T2 = Ts[1].getAsType();
+
+// Let R be COMMON-REF(T1, T2). If T1 and T2 are reference ty

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-31 Thread via cfe-commits


@@ -145,8 +160,6 @@ struct __common_reference_sub_bullet1<_Tp, _Up> {
 

huixie90 wrote:

The origin line 156 does not match the new builtin implementation. the pointer 
bit is missing as P2655R3 is not implemented . do we have a test?

https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-31 Thread via cfe-commits

https://github.com/huixie90 requested changes to this pull request.


https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-31 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 ready_for_review 
https://github.com/llvm/llvm-project/pull/121199
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-31 Thread via cfe-commits

llvmbot wrote:



@llvm/pr-subscribers-clang

@llvm/pr-subscribers-libcxx

Author: Nikolas Klauser (philnik777)


Changes



---

Patch is 40.04 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/121199.diff


9 Files Affected:

- (modified) clang/docs/LanguageExtensions.rst (+17) 
- (modified) clang/include/clang/Basic/BuiltinTemplates.td (+28-2) 
- (modified) clang/include/clang/Sema/Sema.h (+19) 
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+5-87) 
- (modified) clang/lib/Sema/SemaTemplate.cpp (+335-18) 
- (modified) clang/lib/Sema/SemaType.cpp (+75) 
- (added) clang/test/SemaCXX/type-trait-common-reference.cpp (+141) 
- (modified) libcxx/include/__type_traits/common_reference.h (+26-11) 
- (modified) libcxx/include/module.modulemap (+1) 


``diff
diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..6fc86507ca423 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_refernce``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
   QualType BuiltinChangeSigne

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-29 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 19a76935988b306201ed536e99e9094b18006a0f Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 353 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 141 +++
 .../include/__type_traits/common_reference.h  |  37 +-
 libcxx/include/module.modulemap   |   1 +
 9 files changed, 647 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..6fc86507ca423 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_refernce``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualifie

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-29 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 3010ba7ab5392394b37261807fc7cf4cbb205e0c Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 355 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 123 ++
 .../include/__type_traits/common_reference.h  |  36 +-
 8 files changed, 629 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3b8a9cac6587a..6fc86507ca423 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1677,6 +1677,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_refernce``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 066bce61c74c1..762cb851ee04f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15076,15 +15076,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind,
   

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2025-03-06 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 updated 
https://github.com/llvm/llvm-project/pull/121199

>From 55f9d1e5abf5f217e58988742bd7f375d744beb8 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 +
 clang/include/clang/Basic/BuiltinTemplates.td |  30 +-
 clang/include/clang/Sema/Sema.h   |  19 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +
 clang/lib/Sema/SemaTemplate.cpp   | 355 +-
 clang/lib/Sema/SemaType.cpp   |  75 
 .../SemaCXX/type-trait-common-reference.cpp   | 123 ++
 .../include/__type_traits/common_reference.h  |  36 +-
 8 files changed, 629 insertions(+), 118 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 578ee02f09b9b..2cdf78cb0f108 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1657,6 +1657,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_refernce``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/Basic/BuiltinTemplates.td 
b/clang/include/clang/Basic/BuiltinTemplates.td
index d46ce063d2f7e..5c79e89800829 100644
--- a/clang/include/clang/Basic/BuiltinTemplates.td
+++ b/clang/include/clang/Basic/BuiltinTemplates.td
@@ -10,11 +10,11 @@ class TemplateArg {
   string Name = name;
 }
 
-class Template args, string name> : TemplateArg {
+class Template args, string name = ""> : TemplateArg {
   list Args = args;
 }
 
-class Class : TemplateArg {
+class Class : TemplateArg {
   bit IsVariadic = is_variadic;
 }
 
@@ -50,3 +50,29 @@ def __builtin_common_type : BuiltinTemplate<
Template<[Class<"TypeMember">], "HasTypeMember">,
Class<"HasNoTypeMember">,
Class<"Ts", /*is_variadic=*/1>]>;
+
+// template  class,"
+// template  class> class BasicCommonReferenceT,"
+//   template  class CommonTypeT,"
+//   template  class HasTypeMember,"
+//   class HasNoTypeMember,"
+//   class... Ts>"
+def __builtin_common_reference : BuiltinTemplate<
+[Template<[Class<>,
+   Class<>,
+   Template<[Class<>]>,
+   Template<[Class<>]>], "BasicCommonReferenceT">,
+ Template<[Class<"Args", /*is_variadic=*/1>], "CommonTypeT">,
+ Template<[Class<>], "HasTypeMember">,
+ Class<"HasNoTypeMember">,
+ Class<"Ts", /*is_variadic=*/1>]>;
+
+foreach Ref = ["", "lvalue", "rvalue"] in {
+  foreach Const = ["", "const"] in {
+foreach Volatile = ["", "volatile"] in {
+  def __clang_internal_xref_#Ref#Const#Volatile : 
BuiltinTemplate<[Class<>]>;
+}
+  }
+}
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 80177996b48b0..241e6a678b79f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -15026,15 +15026,34 @@ class Sema final : public SemaBase {
   QualType BuiltinDecay(QualType BaseType, SourceLocation Loc);
   QualType BuiltinAddReference(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
+
+  QualType BuiltinAddRValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddRvalueReference,
+   Loc);
+  }
+
+  QualType BuiltinAddLValueReference(QualType BaseType, SourceLocation Loc) {
+return BuiltinAddReference(BaseType, 
UnaryTransformType::AddLvalueReference,
+   Loc);
+  }
+
   QualType BuiltinRemoveExtent(QualType BaseType, UTTKind UKind,
SourceLocation Loc);
   QualType BuiltinRemoveReference(QualType BaseType, UTTKind UKind,
   SourceLocation Loc);
+
+  QualType BuiltinRemoveCVRef(QualType BaseType, SourceLocation Loc) {
+return BuiltinRemoveReference(BaseType, UTTKind::RemoveCVRef, Loc);
+  }
+
   QualType BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind,
   

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2024-12-27 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff f334db92be168876b618db72dc93078ce23ffa89 
e0db7316b2705398a2ac7e69cd1e3e83ece52613 --extensions h,cpp -- 
clang/test/SemaCXX/type-trait-common-reference.cpp 
clang/include/clang/AST/ASTContext.h clang/include/clang/AST/ASTNodeTraverser.h 
clang/include/clang/AST/DeclID.h clang/include/clang/AST/DeclTemplate.h 
clang/include/clang/AST/RecursiveASTVisitor.h 
clang/include/clang/Basic/Builtins.h clang/include/clang/Sema/Sema.h 
clang/lib/AST/ASTContext.cpp clang/lib/AST/ASTImporter.cpp 
clang/lib/AST/DeclBase.cpp clang/lib/AST/DeclTemplate.cpp 
clang/lib/CodeGen/CGDecl.cpp clang/lib/Lex/PPMacroExpansion.cpp 
clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaLookup.cpp 
clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
clang/lib/Sema/SemaType.cpp clang/lib/Serialization/ASTCommon.cpp 
clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp 
clang/tools/libclang/CIndex.cpp libcxx/include/__type_traits/common_reference.h
``





View the diff from clang-format here.


``diff
diff --git a/clang/include/clang/AST/DeclTemplate.h 
b/clang/include/clang/AST/DeclTemplate.h
index b765e0d17c..e94dcdb612 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -1807,9 +1807,7 @@ public:
 return new (C, DC) CVRefQualifyingTemplateDecl(C, DC, Ref);
   }
 
-  SourceRange getSourceRange() const override LLVM_READONLY {
-return {};
-  }
+  SourceRange getSourceRange() const override LLVM_READONLY { return {}; }
 
   CVRefQuals getQuals() { return Quals; }
 };
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 635e2eb348..c43ebb2086 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -1697,11 +1697,9 @@ static TemplateParameterList 
*createBuiltinCommonTypeList(const ASTContext &C,
   nullptr);
 }
 
-static TemplateTypeParmDecl *BICreateTemplateParm(const ASTContext &C,
-  DeclContext *DC,
-  unsigned Depth,
-  unsigned Position,
-  bool ParameterPack = false) {
+static TemplateTypeParmDecl *
+BICreateTemplateParm(const ASTContext &C, DeclContext *DC, unsigned Depth,
+ unsigned Position, bool ParameterPack = false) {
   return TemplateTypeParmDecl::Create(
   C, DC, SourceLocation(), SourceLocation(), Depth, Position,
   /*Id=*/nullptr, /*Typename=*/false, ParameterPack);
@@ -1733,8 +1731,8 @@ createBuiltinCommonReferenceBasicCommonReferenceT(const 
ASTContext &C,
   /*Position=*/0);
 }
 
-static TemplateParameterList *createBuiltinCommonReferenceList(const 
ASTContext &C,
-  DeclContext *DC) {
+static TemplateParameterList *
+createBuiltinCommonReferenceList(const ASTContext &C, DeclContext *DC) {
   // template  class, template  class>
   // class
   auto *BasicCommonReference =
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 4706013ff7..6672fdedd0 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -3232,26 +3232,24 @@ static QualType CondRes(Sema &S, QualType X, QualType 
Y, SourceLocation Loc) {
   Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl());
 
   // false
-  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy,
-VK_PRValue);
+  OpaqueValueExpr CondExpr(SourceLocation(), S.Context.BoolTy, VK_PRValue);
   ExprResult Cond = &CondExpr;
 
   // declval()()
   OpaqueValueExpr LHSExpr(Loc, X.getNonLValueExprType(S.Context),
-  Expr::getValueKindForType(X));
+  Expr::getValueKindForType(X));
   ExprResult LHS = &LHSExpr;
 
   // declval()()
   OpaqueValueExpr RHSExpr(Loc, Y.getNonLValueExprType(S.Context),
-  Expr::getValueKindForType(Y));
+  Expr::getValueKindForType(Y));
   ExprResult RHS = &RHSExpr;
 
   ExprValueKind VK = VK_PRValue;
   ExprObjectKind OK = OK_Ordinary;
 
   // decltype(false ? declval()() : declval()())
-  QualType Result =
-  S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
+  QualType Result = S.CheckConditionalOperands(Cond, LHS, RHS, VK, OK, Loc);
 
   if (SFINAE.hasErrorOccurred())
 return QualType();
@@ -3260,8 +3258,7 @@ static QualType CondRes(Sema &S, QualType X, QualType Y, 
SourceLocation Loc) {
   return Result;
 }
 
-static QualType CommonRef(Sema &S, QualType A, QualType B,
- SourceLocation Loc) {
+static QualType CommonRef(Se

[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)

2024-12-27 Thread Nikolas Klauser via cfe-commits

https://github.com/philnik777 created 
https://github.com/llvm/llvm-project/pull/121199

None

>From e0db7316b2705398a2ac7e69cd1e3e83ece52613 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser 
Date: Fri, 27 Sep 2024 22:11:14 +0200
Subject: [PATCH] [Clang] Add __builtin_common_reference

---
 clang/docs/LanguageExtensions.rst |  17 ++
 clang/include/clang/AST/ASTContext.h  |  13 +
 clang/include/clang/AST/ASTNodeTraverser.h|   4 +
 clang/include/clang/AST/DeclID.h  |   3 +
 clang/include/clang/AST/DeclTemplate.h|  37 +++
 clang/include/clang/AST/RecursiveASTVisitor.h |   4 +
 clang/include/clang/Basic/Builtins.h  |   3 +
 clang/include/clang/Basic/DeclNodes.td|   1 +
 clang/include/clang/Sema/Sema.h   |  19 ++
 clang/lib/AST/ASTContext.cpp  |  31 ++
 clang/lib/AST/ASTImporter.cpp |   3 +
 clang/lib/AST/DeclBase.cpp|   1 +
 clang/lib/AST/DeclTemplate.cpp| 102 +++
 clang/lib/CodeGen/CGDecl.cpp  |   1 +
 clang/lib/Lex/PPMacroExpansion.cpp|   1 +
 clang/lib/Sema/SemaExprCXX.cpp|  92 +-
 clang/lib/Sema/SemaLookup.cpp |   4 +
 clang/lib/Sema/SemaTemplate.cpp   | 275 --
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  |   5 +
 clang/lib/Sema/SemaType.cpp   |  73 +
 clang/lib/Serialization/ASTCommon.cpp |   1 +
 clang/lib/Serialization/ASTReader.cpp |   6 +
 clang/lib/Serialization/ASTWriter.cpp |   2 +
 .../SemaCXX/type-trait-common-reference.cpp   | 120 
 clang/tools/libclang/CIndex.cpp   |   1 +
 .../include/__type_traits/common_reference.h  |  36 ++-
 26 files changed, 738 insertions(+), 117 deletions(-)
 create mode 100644 clang/test/SemaCXX/type-trait-common-reference.cpp

diff --git a/clang/docs/LanguageExtensions.rst 
b/clang/docs/LanguageExtensions.rst
index 3d4f68b818bce7..09311f3e1233d9 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1546,6 +1546,23 @@ Builtin type aliases
 
 Clang provides a few builtin aliases to improve the throughput of certain 
metaprogramming facilities.
 
+__builtin_common_reference
+--
+
+.. code-block:: c++
+
+  template  class, template  
class> class BasicCommonReferenceT,
+template  CommonTypeT,
+template  HasTypeMember,
+class HasNoTypeMember,
+class... Ts>
+  using __builtin_common_reference = ...;
+
+This alias is used for implementing ``std::common_refernce``. If 
``std::common_reference`` should contain a ``type``
+member, it is an alias to ``HasTypeMember``. Otherwse it 
is an alias to ``HasNoTypeMember``. The
+``CommonTypeT`` is usually ``std::common_type_t``. ``BasicCommonReferenceT`` 
is usually an alias template to
+``basic_common_reference::type``.
+
 __builtin_common_type
 -
 
diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 1e89a6805ce9c6..3c18e73cdc391a 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -419,6 +419,9 @@ class ASTContext : public RefCountedBase {
   /// The identifier '__builtin_common_type'.
   mutable IdentifierInfo *BuiltinCommonTypeName = nullptr;
 
+  /// The identifier '__builtin_common_reference'.
+  mutable IdentifierInfo *BuiltinCommonReferenceName = nullptr;
+
   QualType ObjCConstantStringType;
   mutable RecordDecl *CFConstantStringTagDecl = nullptr;
   mutable TypedefDecl *CFConstantStringTypeDecl = nullptr;
@@ -627,6 +630,8 @@ class ASTContext : public RefCountedBase {
   mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
   mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
   mutable BuiltinTemplateDecl *BuiltinCommonTypeDecl = nullptr;
+  mutable BuiltinTemplateDecl *BuiltinCommonReferenceDecl = nullptr;
+  mutable CVRefQualifyingTemplateDecl *CVRefQualifyingDecls[12] = {};
 
   /// The associated SourceManager object.
   SourceManager &SourceMgr;
@@ -1155,6 +1160,8 @@ class ASTContext : public RefCountedBase {
   BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
   BuiltinTemplateDecl *getTypePackElementDecl() const;
   BuiltinTemplateDecl *getBuiltinCommonTypeDecl() const;
+  BuiltinTemplateDecl *getBuiltinCommonReferenceDecl() const;
+  CVRefQualifyingTemplateDecl *getCVRefQualifyingAliasDecl(QualType From) 
const;
 
   // Builtin Types.
   CanQualType VoidTy;
@@ -2072,6 +2079,12 @@ class ASTContext : public RefCountedBase {
 return BuiltinCommonTypeName;
   }
 
+  IdentifierInfo *getBuiltinCommonReferenceName() const {
+if (!BuiltinCommonReferenceName)
+  BuiltinCommonReferenceName = &Idents.get("__builtin_common_reference");
+return BuiltinCommonReferenceName;
+  }
+
   /// Retrieve the Objective-C "instancetype" type, if already known;
   /// otherwise, returns a NULL type;