forked from OSchip/llvm-project
[Feature] Add a builtin for indexing into parameter packs. Patch by Louis Dionne.
This patch adds a __nth_element builtin that allows fetching the n-th type of a parameter pack with very little compile-time overhead. The patch was inspired by r252036 and r252115 by David Majnemer, which add a similar __make_integer_seq builtin for efficiently creating a std::integer_sequence. Reviewed as D15421. http://reviews.llvm.org/D15421 llvm-svn: 274316
This commit is contained in:
parent
762c5ca3ee
commit
6ad68551c3
|
@ -255,6 +255,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
/// The identifier '__make_integer_seq'.
|
||||
mutable IdentifierInfo *MakeIntegerSeqName = nullptr;
|
||||
|
||||
/// The identifier '__type_pack_element'.
|
||||
mutable IdentifierInfo *TypePackElementName = nullptr;
|
||||
|
||||
QualType ObjCConstantStringType;
|
||||
mutable RecordDecl *CFConstantStringTagDecl;
|
||||
mutable TypedefDecl *CFConstantStringTypeDecl;
|
||||
|
@ -410,6 +413,7 @@ private:
|
|||
TranslationUnitDecl *TUDecl;
|
||||
mutable ExternCContextDecl *ExternCContext;
|
||||
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl;
|
||||
mutable BuiltinTemplateDecl *TypePackElementDecl;
|
||||
|
||||
/// \brief The associated SourceManager object.a
|
||||
SourceManager &SourceMgr;
|
||||
|
@ -880,6 +884,7 @@ public:
|
|||
|
||||
ExternCContextDecl *getExternCContextDecl() const;
|
||||
BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
|
||||
BuiltinTemplateDecl *getTypePackElementDecl() const;
|
||||
|
||||
// Builtin Types.
|
||||
CanQualType VoidTy;
|
||||
|
@ -1473,6 +1478,12 @@ public:
|
|||
return MakeIntegerSeqName;
|
||||
}
|
||||
|
||||
IdentifierInfo *getTypePackElementName() const {
|
||||
if (!TypePackElementName)
|
||||
TypePackElementName = &Idents.get("__type_pack_element");
|
||||
return TypePackElementName;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the Objective-C "instancetype" type, if already known;
|
||||
/// otherwise, returns a NULL type;
|
||||
QualType getObjCInstanceType() {
|
||||
|
|
|
@ -1490,8 +1490,8 @@ public:
|
|||
};
|
||||
|
||||
/// \brief Represents the builtin template declaration which is used to
|
||||
/// implement __make_integer_seq. It serves no real purpose beyond existing as
|
||||
/// a place to hold template parameters.
|
||||
/// implement __make_integer_seq and other builtin templates. It serves
|
||||
/// no real purpose beyond existing as a place to hold template parameters.
|
||||
class BuiltinTemplateDecl : public TemplateDecl {
|
||||
void anchor() override;
|
||||
|
||||
|
|
|
@ -219,7 +219,10 @@ private:
|
|||
/// \brief Kinds of BuiltinTemplateDecl.
|
||||
enum BuiltinTemplateKind : int {
|
||||
/// \brief This names the __make_integer_seq BuiltinTemplateDecl.
|
||||
BTK__make_integer_seq
|
||||
BTK__make_integer_seq,
|
||||
|
||||
/// \brief This names the __type_pack_element BuiltinTemplateDecl.
|
||||
BTK__type_pack_element
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -2128,6 +2128,10 @@ def err_integer_sequence_negative_length : Error<
|
|||
def err_integer_sequence_integral_element_type : Error<
|
||||
"integer sequences must have integral element type">;
|
||||
|
||||
// __type_pack_element
|
||||
def err_type_pack_element_out_of_bounds : Error<
|
||||
"a parameter pack may not be accessed at an out of bounds index">;
|
||||
|
||||
// Objective-C++
|
||||
def err_objc_decls_may_only_appear_in_global_scope : Error<
|
||||
"Objective-C declarations may only appear in global scope">;
|
||||
|
|
|
@ -983,13 +983,16 @@ namespace clang {
|
|||
|
||||
/// \brief The internal '__NSConstantString' tag type.
|
||||
PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 15,
|
||||
|
||||
/// \brief The internal '__type_pack_element' template.
|
||||
PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 16,
|
||||
};
|
||||
|
||||
/// \brief The number of declaration IDs that are predefined.
|
||||
///
|
||||
/// For more information about predefined declarations, see the
|
||||
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
|
||||
const unsigned int NUM_PREDEF_DECL_IDS = 16;
|
||||
const unsigned int NUM_PREDEF_DECL_IDS = 17;
|
||||
|
||||
/// \brief Record of updates for a declaration that was modified after
|
||||
/// being deserialized. This can occur within DECLTYPES_BLOCK_ID.
|
||||
|
|
|
@ -742,8 +742,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
|
|||
sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr),
|
||||
BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr),
|
||||
cudaConfigureCallDecl(nullptr), FirstLocalImport(), LastLocalImport(),
|
||||
ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr), SourceMgr(SM),
|
||||
LangOpts(LOpts),
|
||||
ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr),
|
||||
TypePackElementDecl(nullptr), SourceMgr(SM), LangOpts(LOpts),
|
||||
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
|
||||
AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr),
|
||||
PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
|
||||
|
@ -928,6 +928,14 @@ ASTContext::getMakeIntegerSeqDecl() const {
|
|||
return MakeIntegerSeqDecl;
|
||||
}
|
||||
|
||||
BuiltinTemplateDecl *
|
||||
ASTContext::getTypePackElementDecl() const {
|
||||
if (!TypePackElementDecl)
|
||||
TypePackElementDecl = buildBuiltinTemplateDecl(BTK__type_pack_element,
|
||||
getTypePackElementName());
|
||||
return TypePackElementDecl;
|
||||
}
|
||||
|
||||
RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
|
||||
RecordDecl::TagKind TK) const {
|
||||
SourceLocation Loc;
|
||||
|
|
|
@ -1239,11 +1239,34 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
|
|||
Params, SourceLocation());
|
||||
}
|
||||
|
||||
static TemplateParameterList *
|
||||
createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
|
||||
// std::size_t Index
|
||||
TypeSourceInfo *TInfo = C.getTrivialTypeSourceInfo(C.getSizeType());
|
||||
auto *Index = NonTypeTemplateParmDecl::Create(
|
||||
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/0,
|
||||
/*Id=*/nullptr, TInfo->getType(), /*ParameterPack=*/false, TInfo);
|
||||
|
||||
// typename ...T
|
||||
auto *Ts = TemplateTypeParmDecl::Create(
|
||||
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
|
||||
/*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true);
|
||||
Ts->setImplicit(true);
|
||||
|
||||
// template <std::size_t Index, typename ...T>
|
||||
NamedDecl *Params[] = {Index, Ts};
|
||||
return TemplateParameterList::Create(C, SourceLocation(), SourceLocation(),
|
||||
llvm::makeArrayRef(Params),
|
||||
SourceLocation());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
llvm_unreachable("unhandled BuiltinTemplateKind!");
|
||||
|
|
|
@ -1695,6 +1695,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
|
|||
const LangOptions &LangOpts = getLangOpts();
|
||||
return llvm::StringSwitch<bool>(II->getName())
|
||||
.Case("__make_integer_seq", LangOpts.CPlusPlus)
|
||||
.Case("__type_pack_element", LangOpts.CPlusPlus)
|
||||
.Default(false);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -680,10 +680,14 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
|
|||
NameKind == Sema::LookupRedeclarationWithLinkage) {
|
||||
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
|
||||
if (II) {
|
||||
if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName &&
|
||||
II == S.getASTContext().getMakeIntegerSeqName()) {
|
||||
R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
|
||||
return true;
|
||||
if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
|
||||
if (II == S.getASTContext().getMakeIntegerSeqName()) {
|
||||
R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
|
||||
return true;
|
||||
} else if (II == S.getASTContext().getTypePackElementName()) {
|
||||
R.addDecl(S.getASTContext().getTypePackElementDecl());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is a builtin on this (or all) targets, create the decl.
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
|
||||
#include <iterator>
|
||||
using namespace clang;
|
||||
using namespace sema;
|
||||
|
||||
|
@ -2042,7 +2043,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
|
|||
TemplateArgumentListInfo &TemplateArgs) {
|
||||
ASTContext &Context = SemaRef.getASTContext();
|
||||
switch (BTD->getBuiltinTemplateKind()) {
|
||||
case BTK__make_integer_seq:
|
||||
case BTK__make_integer_seq: {
|
||||
// Specializations of __make_integer_seq<S, T, N> are treated like
|
||||
// S<T, 0, ..., N-1>.
|
||||
|
||||
|
@ -2084,6 +2085,29 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
|
|||
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
|
||||
TemplateLoc, SyntheticTemplateArgs);
|
||||
}
|
||||
|
||||
case BTK__type_pack_element:
|
||||
// Specializations of
|
||||
// __type_pack_element<Index, T_1, ..., T_N>
|
||||
// are treated like T_Index.
|
||||
assert(Converted.size() == 2 &&
|
||||
"__type_pack_element should be given an index and a parameter pack");
|
||||
|
||||
// If the Index is out of bounds, the program is ill-formed.
|
||||
TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
|
||||
llvm::APSInt Index = IndexArg.getAsIntegral();
|
||||
assert(Index >= 0 && "the index used with __type_pack_element should be of "
|
||||
"type std::size_t, and hence be non-negative");
|
||||
if (Index >= Ts.pack_size()) {
|
||||
SemaRef.Diag(TemplateArgs[0].getLocation(),
|
||||
diag::err_type_pack_element_out_of_bounds);
|
||||
return QualType();
|
||||
}
|
||||
|
||||
// We simply return the type at index `Index`.
|
||||
auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
|
||||
return Nth->getAsType();
|
||||
}
|
||||
llvm_unreachable("unexpected BuiltinTemplateDecl!");
|
||||
}
|
||||
|
||||
|
|
|
@ -6428,6 +6428,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
|
|||
|
||||
case PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID:
|
||||
return Context.getCFConstantStringTagDecl();
|
||||
|
||||
case PREDEF_DECL_TYPE_PACK_ELEMENT_ID:
|
||||
return Context.getTypePackElementDecl();
|
||||
}
|
||||
llvm_unreachable("PredefinedDeclIDs unknown enum value");
|
||||
}
|
||||
|
|
|
@ -4191,6 +4191,8 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
|
|||
PREDEF_DECL_CF_CONSTANT_STRING_ID);
|
||||
RegisterPredefDecl(Context.CFConstantStringTagDecl,
|
||||
PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID);
|
||||
RegisterPredefDecl(Context.TypePackElementDecl,
|
||||
PREDEF_DECL_TYPE_PACK_ELEMENT_ID);
|
||||
|
||||
// Build a record containing all of the tentative definitions in this file, in
|
||||
// TentativeDefinitions order. Generally, this record will be empty for
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// RUN: %clang_cc1 -std=c++14 -x c++-header %s -emit-pch -o %t.pch
|
||||
// RUN: %clang_cc1 -std=c++14 -x c++ /dev/null -include-pch %t.pch
|
||||
|
||||
template <int i>
|
||||
struct X { };
|
||||
|
||||
using SizeT = decltype(sizeof(int));
|
||||
|
||||
template <SizeT i, typename ...T>
|
||||
using TypePackElement = __type_pack_element<i, T...>;
|
||||
|
||||
void fn1() {
|
||||
X<0> x0 = TypePackElement<0, X<0>, X<1>, X<2>>{};
|
||||
X<1> x1 = TypePackElement<1, X<0>, X<1>, X<2>>{};
|
||||
X<2> x2 = TypePackElement<2, X<0>, X<1>, X<2>>{};
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
|
||||
static_assert(__has_builtin(__type_pack_element), "");
|
||||
|
||||
using SizeT = decltype(sizeof(int));
|
||||
|
||||
template <SizeT i, typename ...T>
|
||||
using TypePackElement = __type_pack_element<i, T...>;
|
||||
|
||||
template <int i>
|
||||
struct X;
|
||||
|
||||
static_assert(__is_same(TypePackElement<0, X<0>>, X<0>), "");
|
||||
|
||||
static_assert(__is_same(TypePackElement<0, X<0>, X<1>>, X<0>), "");
|
||||
static_assert(__is_same(TypePackElement<1, X<0>, X<1>>, X<1>), "");
|
||||
|
||||
static_assert(__is_same(TypePackElement<0, X<0>, X<1>, X<2>>, X<0>), "");
|
||||
static_assert(__is_same(TypePackElement<1, X<0>, X<1>, X<2>>, X<1>), "");
|
||||
static_assert(__is_same(TypePackElement<2, X<0>, X<1>, X<2>>, X<2>), "");
|
||||
|
||||
static_assert(__is_same(TypePackElement<0, X<0>, X<1>, X<2>, X<3>>, X<0>), "");
|
||||
static_assert(__is_same(TypePackElement<1, X<0>, X<1>, X<2>, X<3>>, X<1>), "");
|
||||
static_assert(__is_same(TypePackElement<2, X<0>, X<1>, X<2>, X<3>>, X<2>), "");
|
||||
static_assert(__is_same(TypePackElement<3, X<0>, X<1>, X<2>, X<3>>, X<3>), "");
|
||||
|
||||
static_assert(__is_same(TypePackElement<0, X<0>, X<1>, X<2>, X<3>, X<4>>, X<0>), "");
|
||||
static_assert(__is_same(TypePackElement<1, X<0>, X<1>, X<2>, X<3>, X<4>>, X<1>), "");
|
||||
static_assert(__is_same(TypePackElement<2, X<0>, X<1>, X<2>, X<3>, X<4>>, X<2>), "");
|
||||
static_assert(__is_same(TypePackElement<3, X<0>, X<1>, X<2>, X<3>, X<4>>, X<3>), "");
|
||||
static_assert(__is_same(TypePackElement<4, X<0>, X<1>, X<2>, X<3>, X<4>>, X<4>), "");
|
||||
|
||||
static_assert(__is_same(TypePackElement<0, X<0>, X<1>, X<2>, X<3>, X<4>, X<5>>, X<0>), "");
|
||||
static_assert(__is_same(TypePackElement<1, X<0>, X<1>, X<2>, X<3>, X<4>, X<5>>, X<1>), "");
|
||||
static_assert(__is_same(TypePackElement<2, X<0>, X<1>, X<2>, X<3>, X<4>, X<5>>, X<2>), "");
|
||||
static_assert(__is_same(TypePackElement<3, X<0>, X<1>, X<2>, X<3>, X<4>, X<5>>, X<3>), "");
|
||||
static_assert(__is_same(TypePackElement<4, X<0>, X<1>, X<2>, X<3>, X<4>, X<5>>, X<4>), "");
|
||||
static_assert(__is_same(TypePackElement<5, X<0>, X<1>, X<2>, X<3>, X<4>, X<5>>, X<5>), "");
|
||||
|
||||
// Test __type_pack_element with more than 2 top-level template arguments.
|
||||
static_assert(__is_same(__type_pack_element<5, X<0>, X<1>, X<2>, X<3>, X<4>, X<5>>, X<5>), "");
|
||||
|
||||
template <SizeT Index, typename ...T>
|
||||
using ErrorTypePackElement1 = __type_pack_element<Index, T...>; // expected-error{{may not be accessed at an out of bounds index}}
|
||||
using illformed1 = ErrorTypePackElement1<3, X<0>, X<1>>; // expected-note{{in instantiation}}
|
Loading…
Reference in New Issue