Skip to content

Commit

Permalink
[Clang] Add __builtin_common_type (#99473)
Browse files Browse the repository at this point in the history
This implements the logic of the `common_type` base template as a
builtin alias. If there should be no `type` member, an empty class is
returned. Otherwise a specialization of a `type_identity`-like class is
returned. The base template (i.e. `std::common_type`) as well as the
empty class and `type_identity`-like struct are given as arguments to
the builtin.
  • Loading branch information
philnik777 authored Sep 22, 2024
1 parent 15e6b5d commit f5be5cd
Show file tree
Hide file tree
Showing 16 changed files with 531 additions and 6 deletions.
40 changes: 40 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1516,6 +1516,46 @@ Attributes (N2335) C2
``#embed`` (N3017) C23 C89, C++
============================================ ================================ ============= =============

Builtin type aliases
====================

Clang provides a few builtin aliases to improve the throughput of certain metaprogramming facilities.

__builtin_common_type
---------------------

.. code-block:: c++

template <template <class... Args> class BaseTemplate,
template <class TypeMember> class HasTypeMember,
class HasNoTypeMember,
class... Ts>
using __builtin_common_type = ...;

This alias is used for implementing ``std::common_type``. If ``std::common_type`` should contain a ``type`` member,
it is an alias to ``HasTypeMember<TheCommonType>``. Otherwise it is an alias to ``HasNoTypeMember``. The
``BaseTemplate`` is usually ``std::common_type``. ``Ts`` are the arguments to ``std::common_type``.

__type_pack_element
-------------------

.. code-block:: c++

template <std::size_t Index, class... Ts>
using __type_pack_element = ...;

This alias returns the type at ``Index`` in the parameter pack ``Ts``.

__make_integer_seq
------------------

.. code-block:: c++

template <template <class IntSeqT, IntSeqT... Ints> class IntSeq, class T, T N>
using __make_integer_seq = ...;

This alias returns ``IntSeq`` instantiated with ``IntSeqT = T``and ``Ints`` being the pack ``0, ..., N - 1``.

Type Trait Primitives
=====================

Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ C++ Language Changes

- Add ``__builtin_elementwise_popcount`` builtin for integer types only.

- The builtin type alias ``__builtin_common_type`` has been added to improve the
performance of ``std::common_type``.

C++2c Feature Support
^^^^^^^^^^^^^^^^^^^^^

Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// The identifier '__type_pack_element'.
mutable IdentifierInfo *TypePackElementName = nullptr;

/// The identifier '__builtin_common_type'.
mutable IdentifierInfo *BuiltinCommonTypeName = nullptr;

QualType ObjCConstantStringType;
mutable RecordDecl *CFConstantStringTagDecl = nullptr;
mutable TypedefDecl *CFConstantStringTypeDecl = nullptr;
Expand Down Expand Up @@ -610,6 +613,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable ExternCContextDecl *ExternCContext = nullptr;
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl = nullptr;
mutable BuiltinTemplateDecl *TypePackElementDecl = nullptr;
mutable BuiltinTemplateDecl *BuiltinCommonTypeDecl = nullptr;

/// The associated SourceManager object.
SourceManager &SourceMgr;
Expand Down Expand Up @@ -1134,6 +1138,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
ExternCContextDecl *getExternCContextDecl() const;
BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
BuiltinTemplateDecl *getTypePackElementDecl() const;
BuiltinTemplateDecl *getBuiltinCommonTypeDecl() const;

// Builtin Types.
CanQualType VoidTy;
Expand Down Expand Up @@ -2025,6 +2030,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
return TypePackElementName;
}

IdentifierInfo *getBuiltinCommonTypeName() const {
if (!BuiltinCommonTypeName)
BuiltinCommonTypeName = &Idents.get("__builtin_common_type");
return BuiltinCommonTypeName;
}

/// Retrieve the Objective-C "instancetype" type, if already known;
/// otherwise, returns a NULL type;
QualType getObjCInstanceType() {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/DeclID.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ enum PredefinedDeclIDs {
/// The internal '__type_pack_element' template.
PREDEF_DECL_TYPE_PACK_ELEMENT_ID,

/// The internal '__builtin_common_type' template.
PREDEF_DECL_COMMON_TYPE_ID,

/// The number of declaration IDs that are predefined.
NUM_PREDEF_DECL_IDS
};
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/Builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,10 @@ enum BuiltinTemplateKind : int {
BTK__make_integer_seq,

/// This names the __type_pack_element BuiltinTemplateDecl.
BTK__type_pack_element
BTK__type_pack_element,

/// This names the __builtin_common_type BuiltinTemplateDecl.
BTK__builtin_common_type,
};

} // end namespace clang
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1184,6 +1184,13 @@ ASTContext::getTypePackElementDecl() const {
return TypePackElementDecl;
}

BuiltinTemplateDecl *ASTContext::getBuiltinCommonTypeDecl() const {
if (!BuiltinCommonTypeDecl)
BuiltinCommonTypeDecl = buildBuiltinTemplateDecl(
BTK__builtin_common_type, getBuiltinCommonTypeName());
return BuiltinCommonTypeDecl;
}

RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
RecordDecl::TagKind TK) const {
SourceLocation Loc;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5467,6 +5467,9 @@ ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
case BuiltinTemplateKind::BTK__type_pack_element:
ToD = Importer.getToContext().getTypePackElementDecl();
break;
case BuiltinTemplateKind::BTK__builtin_common_type:
ToD = Importer.getToContext().getBuiltinCommonTypeDecl();
break;
}
assert(ToD && "BuiltinTemplateDecl of unsupported kind!");
Importer.MapImported(D, ToD);
Expand Down
56 changes: 56 additions & 0 deletions clang/lib/AST/DeclTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1608,13 +1608,69 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
nullptr);
}

static TemplateParameterList *createBuiltinCommonTypeList(const ASTContext &C,
DeclContext *DC) {
// class... Args
auto *Args =
TemplateTypeParmDecl::Create(C, DC, SourceLocation(), SourceLocation(),
/*Depth=*/1, /*Position=*/0, /*Id=*/nullptr,
/*Typename=*/false, /*ParameterPack=*/true);

// <class... Args>
auto *BaseTemplateList = TemplateParameterList::Create(
C, SourceLocation(), SourceLocation(), Args, SourceLocation(), nullptr);

// template <class... Args> class BaseTemplate
auto *BaseTemplate = TemplateTemplateParmDecl::Create(
C, DC, SourceLocation(), /*Depth=*/0, /*Position=*/0,
/*ParameterPack=*/false, /*Id=*/nullptr,
/*Typename=*/false, BaseTemplateList);

// class TypeMember
auto *TypeMember =
TemplateTypeParmDecl::Create(C, DC, SourceLocation(), SourceLocation(),
/*Depth=*/1, /*Position=*/0, /*Id=*/nullptr,
/*Typename=*/false, /*ParameterPack=*/false);

// <class TypeMember>
auto *HasTypeMemberList =
TemplateParameterList::Create(C, SourceLocation(), SourceLocation(),
TypeMember, SourceLocation(), nullptr);

// template <class TypeMember> class HasTypeMember
auto *HasTypeMember = TemplateTemplateParmDecl::Create(
C, DC, SourceLocation(), /*Depth=*/0, /*Position=*/1,
/*ParameterPack=*/false, /*Id=*/nullptr,
/*Typename=*/false, HasTypeMemberList);

// class HasNoTypeMember
auto *HasNoTypeMember = TemplateTypeParmDecl::Create(
C, DC, {}, {}, /*Depth=*/0, /*Position=*/2, /*Id=*/nullptr,
/*Typename=*/false, /*ParameterPack=*/false);

// class... Ts
auto *Ts = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/3,
/*Id=*/nullptr, /*Typename=*/false, /*ParameterPack=*/true);

// template <template <class... Args> class BaseTemplate,
// template <class TypeMember> class HasTypeMember, class HasNoTypeMember,
// class... Ts>
return TemplateParameterList::Create(
C, SourceLocation(), SourceLocation(),
{BaseTemplate, HasTypeMember, HasNoTypeMember, Ts}, SourceLocation(),
nullptr);
}

static TemplateParameterList *createBuiltinTemplateParameterList(
const ASTContext &C, DeclContext *DC, BuiltinTemplateKind BTK) {
switch (BTK) {
case BTK__make_integer_seq:
return createMakeIntegerSeqParameterList(C, DC);
case BTK__type_pack_element:
return createTypePackElementParameterList(C, DC);
case BTK__builtin_common_type:
return createBuiltinCommonTypeList(C, DC);
}

llvm_unreachable("unhandled BuiltinTemplateKind!");
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Lex/PPMacroExpansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1836,6 +1836,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
// Report builtin templates as being builtins.
.Case("__make_integer_seq", getLangOpts().CPlusPlus)
.Case("__type_pack_element", getLangOpts().CPlusPlus)
.Case("__builtin_common_type", getLangOpts().CPlusPlus)
// Likewise for some builtin preprocessor macros.
// FIXME: This is inconsistent; we usually suggest detecting
// builtin macros via #ifdef. Don't add more cases here.
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -928,10 +928,15 @@ bool Sema::LookupBuiltin(LookupResult &R) {
if (II == getASTContext().getMakeIntegerSeqName()) {
R.addDecl(getASTContext().getMakeIntegerSeqDecl());
return true;
} else if (II == getASTContext().getTypePackElementName()) {
}
if (II == getASTContext().getTypePackElementName()) {
R.addDecl(getASTContext().getTypePackElementDecl());
return true;
}
if (II == getASTContext().getBuiltinCommonTypeName()) {
R.addDecl(getASTContext().getBuiltinCommonTypeDecl());
return true;
}
}

// Check if this is an OpenCL Builtin, and if so, insert its overloads.
Expand Down
Loading

0 comments on commit f5be5cd

Please sign in to comment.