[Sema] Implement __make_integer_seq

This new builtin template allows for incredibly fast instantiations of
templates like std::integer_sequence.

Performance numbers follow:
My work station has 64 GB of ram + 20 Xeon Cores at 2.8 GHz.

__make_integer_seq<std::integer_sequence, int, 90000> takes 0.25
seconds.

std::make_integer_sequence<int, 90000> takes unbound time, it is still
running.  Clang is consuming gigabytes of memory.

Differential Revision: http://reviews.llvm.org/D13786

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@252036 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Majnemer 2015-11-04 03:40:30 +00:00
parent 0c29653a59
commit 6bb02a27b9
23 changed files with 308 additions and 4 deletions

View File

@ -70,6 +70,7 @@ namespace clang {
class VTableContextBase;
namespace Builtin { class Context; }
enum BuiltinTemplateKind : int;
namespace comments {
class FullComment;
@ -246,6 +247,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// The identifier 'NSCopying'.
IdentifierInfo *NSCopyingName = nullptr;
/// The identifier '__make_integer_seq'.
mutable IdentifierInfo *MakeIntegerSeqName = nullptr;
QualType ObjCConstantStringType;
mutable RecordDecl *CFConstantStringTypeDecl;
@ -399,6 +403,7 @@ private:
TranslationUnitDecl *TUDecl;
mutable ExternCContextDecl *ExternCContext;
mutable BuiltinTemplateDecl *MakeIntegerSeqDecl;
/// \brief The associated SourceManager object.a
SourceManager &SourceMgr;
@ -868,6 +873,7 @@ public:
TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
ExternCContextDecl *getExternCContextDecl() const;
BuiltinTemplateDecl *getMakeIntegerSeqDecl() const;
// Builtin Types.
CanQualType VoidTy;
@ -941,6 +947,9 @@ public:
void PrintStats() const;
const SmallVectorImpl<Type *>& getTypes() const { return Types; }
BuiltinTemplateDecl *buildBuiltinTemplateDecl(BuiltinTemplateKind BTK,
const IdentifierInfo *II) const;
/// \brief Create a new implicit TU-level CXXRecordDecl or RecordDecl
/// declaration.
RecordDecl *buildImplicitRecord(StringRef Name,
@ -1444,6 +1453,12 @@ public:
return NSCopyingName;
}
IdentifierInfo *getMakeIntegerSeqName() const {
if (!MakeIntegerSeqName)
MakeIntegerSeqName = &Idents.get("__make_integer_seq");
return MakeIntegerSeqName;
}
/// \brief Retrieve the Objective-C "instancetype" type, if already known;
/// otherwise, returns a NULL type;
QualType getObjCInstanceType() {

View File

@ -1551,6 +1551,10 @@ DEF_TRAVERSE_DECL(FunctionTemplateDecl, {
TRY_TO(TraverseFunctionInstantiations(D));
})
DEF_TRAVERSE_DECL(BuiltinTemplateDecl, {
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
})
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
// D is the "T" in something like
// template <template <typename> class T> class container { };

View File

@ -25,6 +25,7 @@
namespace clang {
enum BuiltinTemplateKind : int;
class TemplateParameterList;
class TemplateDecl;
class RedeclarableTemplateDecl;
@ -1490,6 +1491,35 @@ public:
friend TrailingObjects;
};
/// \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.
class BuiltinTemplateDecl : public TemplateDecl {
void anchor() override;
BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
DeclarationName Name, BuiltinTemplateKind BTK);
BuiltinTemplateKind BTK;
public:
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == BuiltinTemplate; }
static BuiltinTemplateDecl *Create(const ASTContext &C, DeclContext *DC,
DeclarationName Name,
BuiltinTemplateKind BTK) {
return new (C, DC) BuiltinTemplateDecl(C, DC, Name, BTK);
}
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange();
}
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
};
/// \brief Represents a class template specialization, which refers to
/// a class template with a given set of template arguments.
///

View File

@ -1603,6 +1603,10 @@ DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
})
DEF_TRAVERSE_DECL(BuiltinTemplateDecl, {
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
})
DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
// D is the "T" in something like "template<typename T> class vector;"
if (D->getTypeForDecl())

View File

@ -205,5 +205,12 @@ private:
};
}
/// \brief Kinds of BuiltinTemplateDecl.
enum BuiltinTemplateKind : int {
/// \brief This names the __make_integer_seq BuiltinTemplateDecl.
BTK__make_integer_seq
};
} // end namespace clang
#endif

View File

@ -59,6 +59,7 @@ def Named : Decl<1>;
def VarTemplate : DDecl<RedeclarableTemplate>;
def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
def TemplateTemplateParm : DDecl<Template>;
def BuiltinTemplate : DDecl<Template>;
def Using : DDecl<Named>;
def UsingShadow : DDecl<Named>;
def ObjCMethod : DDecl<Named>, DeclContext;

View File

@ -1995,7 +1995,13 @@ def err_concept_decl_invalid_specifiers : Error<
def warn_cxx98_compat_unicode_type : Warning<
"'%0' type specifier is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
// __make_integer_seq
def err_integer_sequence_negative_length : Error<
"integer sequences must have non-negative sequence length">;
def err_integer_sequence_integral_element_type : Error<
"integer sequences must have integral element type">;
// Objective-C++
def err_objc_decls_may_only_appear_in_global_scope : Error<
"Objective-C declarations may only appear in global scope">;

View File

@ -982,13 +982,16 @@ namespace clang {
/// \brief The extern "C" context.
PREDEF_DECL_EXTERN_C_CONTEXT_ID = 12,
/// \brief The internal '__make_integer_seq' template.
PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 13,
};
/// \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 = 13;
const unsigned int NUM_PREDEF_DECL_IDS = 14;
/// \brief Record code for a list of local redeclarations of a declaration.
const unsigned int LOCAL_REDECLARATIONS = 50;

View File

@ -744,7 +744,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
ucontext_tDecl(nullptr), BlockDescriptorType(nullptr),
BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr),
FirstLocalImport(), LastLocalImport(), ExternCContext(nullptr),
SourceMgr(SM), LangOpts(LOpts),
MakeIntegerSeqDecl(nullptr), SourceMgr(SM), LangOpts(LOpts),
SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)),
AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr),
PrintingPolicy(LOpts), Idents(idents), Selectors(sels),
@ -913,6 +913,24 @@ ExternCContextDecl *ASTContext::getExternCContextDecl() const {
return ExternCContext;
}
BuiltinTemplateDecl *
ASTContext::buildBuiltinTemplateDecl(BuiltinTemplateKind BTK,
const IdentifierInfo *II) const {
auto *BuiltinTemplate = BuiltinTemplateDecl::Create(*this, TUDecl, II, BTK);
BuiltinTemplate->setImplicit();
TUDecl->addDecl(BuiltinTemplate);
return BuiltinTemplate;
}
BuiltinTemplateDecl *
ASTContext::getMakeIntegerSeqDecl() const {
if (!MakeIntegerSeqDecl)
MakeIntegerSeqDecl = buildBuiltinTemplateDecl(BTK__make_integer_seq,
getMakeIntegerSeqName());
return MakeIntegerSeqDecl;
}
RecordDecl *ASTContext::buildImplicitRecord(StringRef Name,
RecordDecl::TagKind TK) const {
SourceLocation Loc;

View File

@ -21,6 +21,7 @@
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
@ -447,6 +448,7 @@ namespace {
const ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D);
void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D);
void VisitVarTemplateDecl(const VarTemplateDecl *D);
void VisitVarTemplateSpecializationDecl(
const VarTemplateSpecializationDecl *D);
@ -1333,6 +1335,11 @@ void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
VisitTemplateDecl(D, false);
}
void ASTDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) {
dumpName(D);
dumpTemplateParameters(D->getTemplateParameters());
}
void ASTDumper::VisitVarTemplateSpecializationDecl(
const VarTemplateSpecializationDecl *D) {
dumpTemplateArgumentList(D->getTemplateArgs());

View File

@ -639,6 +639,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ExternCContext:
case UsingDirective:
case BuiltinTemplate:
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
case ClassScopeFunctionSpecialization:

View File

@ -18,6 +18,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
#include <memory>
@ -1191,3 +1192,69 @@ VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) VarTemplatePartialSpecializationDecl(C);
}
static TemplateParameterList *
createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) {
// typename T
auto *T = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/1, /*Position=*/0,
/*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false);
T->setImplicit(true);
// T ...Ints
TypeSourceInfo *TI =
C.getTrivialTypeSourceInfo(QualType(T->getTypeForDecl(), 0));
auto *N = NonTypeTemplateParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
/*Id=*/nullptr, TI->getType(), /*ParameterPack=*/true, TI);
N->setImplicit(true);
// <typename T, T ...Ints>
NamedDecl *P[2] = {T, N};
auto *TPL = TemplateParameterList::Create(
C, SourceLocation(), SourceLocation(), P, 2, SourceLocation());
// template <typename T, ...Ints> class IntSeq
auto *TemplateTemplateParm = TemplateTemplateParmDecl::Create(
C, DC, SourceLocation(), /*Depth=*/0, /*Position=*/0,
/*ParameterPack=*/false, /*Id=*/nullptr, TPL);
TemplateTemplateParm->setImplicit(true);
// typename T
auto *TemplateTypeParm = TemplateTypeParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1,
/*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false);
TemplateTypeParm->setImplicit(true);
// T N
TypeSourceInfo *TInfo = C.getTrivialTypeSourceInfo(
QualType(TemplateTypeParm->getTypeForDecl(), 0));
auto *NonTypeTemplateParm = NonTypeTemplateParmDecl::Create(
C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/2,
/*Id=*/nullptr, TInfo->getType(), /*ParameterPack=*/false, TInfo);
NamedDecl *Params[] = {TemplateTemplateParm, TemplateTypeParm,
NonTypeTemplateParm};
// template <template <typename T, T ...Ints> class IntSeq, typename T, T N>
return TemplateParameterList::Create(C, SourceLocation(), SourceLocation(),
Params, 3, SourceLocation());
}
static TemplateParameterList *createBuiltinTemplateParameterList(
const ASTContext &C, DeclContext *DC, BuiltinTemplateKind BTK) {
switch (BTK) {
case BTK__make_integer_seq:
return createMakeIntegerSeqParameterList(C, DC);
}
llvm_unreachable("unhandled BuiltinTemplateKind!");
}
void BuiltinTemplateDecl::anchor() {}
BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
DeclarationName Name,
BuiltinTemplateKind BTK)
: TemplateDecl(BuiltinTemplate, DC, SourceLocation(), Name,
createBuiltinTemplateParameterList(C, DC, BTK)),
BTK(BTK) {}

View File

@ -35,6 +35,7 @@ using namespace CodeGen;
void CodeGenFunction::EmitDecl(const Decl &D) {
switch (D.getKind()) {
case Decl::BuiltinTemplate:
case Decl::TranslationUnit:
case Decl::ExternCContext:
case Decl::Namespace:

View File

@ -627,6 +627,11 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
R.addDecl(S.getASTContext().getFloat128StubType());
return true;
}
if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName &&
II == S.getASTContext().getMakeIntegerSeqName()) {
R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
return true;
}
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {

View File

@ -18,6 +18,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
@ -208,7 +209,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
R.suppressDiagnostics();
} else {
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD));
isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
isa<BuiltinTemplateDecl>(TD));
TemplateKind =
isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
}
@ -2017,6 +2019,58 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) {
}
}
static QualType
checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
const SmallVectorImpl<TemplateArgument> &Converted,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext();
switch (BTD->getBuiltinTemplateKind()) {
case BTK__make_integer_seq:
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
// C++14 [inteseq.intseq]p1:
// T shall be an integer type.
if (!Converted[1].getAsType()->isIntegralType(Context)) {
SemaRef.Diag(TemplateArgs[1].getLocation(),
diag::err_integer_sequence_integral_element_type);
return QualType();
}
// C++14 [inteseq.make]p1:
// If N is negative the program is ill-formed.
TemplateArgument NumArgsArg = Converted[2];
llvm::APSInt NumArgs = NumArgsArg.getAsIntegral();
if (NumArgs < 0) {
SemaRef.Diag(TemplateArgs[2].getLocation(),
diag::err_integer_sequence_negative_length);
return QualType();
}
QualType ArgTy = NumArgsArg.getIntegralType();
TemplateArgumentListInfo SyntheticTemplateArgs;
// The type argument gets reused as the first template argument in the
// synthetic template argument list.
SyntheticTemplateArgs.addArgument(TemplateArgs[1]);
// Expand N into 0 ... N-1.
for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
I < NumArgs; ++I) {
TemplateArgument TA(Context, I, ArgTy);
Expr *E = SemaRef.BuildExpressionFromIntegralTemplateArgument(
TA, TemplateArgs[2].getLocation())
.getAs<Expr>();
SyntheticTemplateArgs.addArgument(
TemplateArgumentLoc(TemplateArgument(E), E));
}
// The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to.
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
TemplateLoc, SyntheticTemplateArgs);
}
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
QualType Sema::CheckTemplateIdType(TemplateName Name,
SourceLocation TemplateLoc,
TemplateArgumentListInfo &TemplateArgs) {
@ -2171,6 +2225,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
CanonType = Context.getTypeDeclType(Decl);
assert(isa<RecordType>(CanonType) &&
"type of non-dependent specialization is not a RecordType");
} else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) {
CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc,
TemplateArgs);
}
// Build the fully-sugared type for this class template

View File

@ -922,6 +922,11 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
llvm_unreachable("EnumConstantDecls can only occur within EnumDecls.");
}
Decl *
TemplateDeclInstantiator::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
llvm_unreachable("BuiltinTemplateDecls cannot be instantiated.");
}
Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);

View File

@ -329,6 +329,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::BuiltinTemplate:
return false;
// These indirectly derive from Redeclarable<T> but are not actually

View File

@ -6412,6 +6412,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
case PREDEF_DECL_EXTERN_C_CONTEXT_ID:
return Context.getExternCContextDecl();
case PREDEF_DECL_MAKE_INTEGER_SEQ_ID:
return Context.getMakeIntegerSeqDecl();
}
llvm_unreachable("PredefinedDeclIDs unknown enum value");
}

View File

@ -293,6 +293,7 @@ namespace clang {
DeclID VisitTemplateDecl(TemplateDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D);
void VisitVarTemplateDecl(VarTemplateDecl *D);
void VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
@ -1856,6 +1857,10 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) {
}
}
void ASTDeclReader::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) {
llvm_unreachable("BuiltinTemplates are not serialized");
}
/// TODO: Unify with ClassTemplateDecl version?
/// May require unifying ClassTemplateDecl and
/// VarTemplateDecl beyond TemplateDecl...

View File

@ -4136,6 +4136,8 @@ uint64_t ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
RegisterPredefDecl(Context.BuiltinMSVaListDecl,
PREDEF_DECL_BUILTIN_MS_VA_LIST_ID);
RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID);
RegisterPredefDecl(Context.MakeIntegerSeqDecl,
PREDEF_DECL_MAKE_INTEGER_SEQ_ID);
// Build a record containing all of the tentative definitions in this file, in
// TentativeDefinitions order. Generally, this record will be empty for

View File

@ -0,0 +1,14 @@
// 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 <class T, T... I>
struct Seq {
static constexpr T PackSize = sizeof...(I);
};
template <typename T, T N>
using MakeSeq = __make_integer_seq<Seq, T, N>;
void fn1() {
MakeSeq<int, 3> x;
}

View File

@ -0,0 +1,47 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
template <class T, T... I>
struct Seq {
static constexpr T PackSize = sizeof...(I);
};
template <typename T, T N>
using MakeSeq = __make_integer_seq<Seq, T, N>;
static_assert(__is_same(MakeSeq<int, 0>, Seq<int>), "");
static_assert(__is_same(MakeSeq<int, 1>, Seq<int, 0>), "");
static_assert(__is_same(MakeSeq<int, 2>, Seq<int, 0, 1>), "");
static_assert(__is_same(MakeSeq<int, 3>, Seq<int, 0, 1, 2>), "");
static_assert(__is_same(MakeSeq<int, 4>, Seq<int, 0, 1, 2, 3>), "");
static_assert(__is_same(MakeSeq<unsigned int, 0U>, Seq<unsigned int>), "");
static_assert(__is_same(MakeSeq<unsigned int, 1U>, Seq<unsigned int, 0U>), "");
static_assert(__is_same(MakeSeq<unsigned int, 2U>, Seq<unsigned int, 0U, 1U>), "");
static_assert(__is_same(MakeSeq<unsigned int, 3U>, Seq<unsigned int, 0U, 1U, 2U>), "");
static_assert(__is_same(MakeSeq<unsigned int, 4U>, Seq<unsigned int, 0U, 1U, 2U, 3U>), "");
static_assert(__is_same(MakeSeq<long long, 0LL>, Seq<long long>), "");
static_assert(__is_same(MakeSeq<long long, 1LL>, Seq<long long, 0LL>), "");
static_assert(__is_same(MakeSeq<long long, 2LL>, Seq<long long, 0LL, 1LL>), "");
static_assert(__is_same(MakeSeq<long long, 3LL>, Seq<long long, 0LL, 1LL, 2LL>), "");
static_assert(__is_same(MakeSeq<long long, 4LL>, Seq<long long, 0LL, 1LL, 2LL, 3LL>), "");
static_assert(__is_same(MakeSeq<unsigned long long, 0ULL>, Seq<unsigned long long>), "");
static_assert(__is_same(MakeSeq<unsigned long long, 1ULL>, Seq<unsigned long long, 0ULL>), "");
static_assert(__is_same(MakeSeq<unsigned long long, 2ULL>, Seq<unsigned long long, 0ULL, 1ULL>), "");
static_assert(__is_same(MakeSeq<unsigned long long, 3ULL>, Seq<unsigned long long, 0ULL, 1ULL, 2ULL>), "");
static_assert(__is_same(MakeSeq<unsigned long long, 4ULL>, Seq<unsigned long long, 0ULL, 1ULL, 2ULL, 3ULL>), "");
template <typename T, T N>
using ErrorSeq = __make_integer_seq<Seq, T, N>; // expected-error{{must have non-negative sequence length}} \
expected-error{{must have integral element type}}
enum Color : int { Red,
Green,
Blue };
using illformed1 = ErrorSeq<Color, Blue>; // expected-note{{in instantiation}}
using illformed2 = ErrorSeq<int, -5>;
template <typename T, T N> void f() {}
__make_integer_seq<f, int, 0> x; // expected-error{{template template parameter must be a class template or type alias template}}

View File

@ -5110,6 +5110,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::ObjCTypeParam:
case Decl::BuiltinTemplate:
return C;
// Declaration kinds that don't make any sense here, but are