[clang] [libcxx] [Clang] Add __builtin_common_reference (PR #121199)
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)
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)
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)
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)
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)
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)
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)
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)
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)
@@ -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)
@@ -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)
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)
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)
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)
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)
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)
@@ -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)
@@ -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)
@@ -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)
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)
@@ -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)
@@ -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)
@@ -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)
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)
@@ -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)
@@ -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)
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)
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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
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)
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)
@@ -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)
@@ -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)
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)
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)
@@ -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)
@@ -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)
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)
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)
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)
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)
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)
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)
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)
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;
