P0217R3: template instantiation support for decomposition declarations.
llvm-svn: 278458
This commit is contained in:
parent
1dc8a42281
commit
3997b1b427
|
@ -4011,6 +4011,12 @@ public:
|
|||
// within a default initializer.
|
||||
if (isa<FieldDecl>(ExtendingDecl))
|
||||
return SD_Automatic;
|
||||
// FIXME: This only works because storage class specifiers are not allowed
|
||||
// on decomposition declarations.
|
||||
if (isa<BindingDecl>(ExtendingDecl))
|
||||
return ExtendingDecl->getDeclContext()->isFunctionOrMethod()
|
||||
? SD_Automatic
|
||||
: SD_Static;
|
||||
return cast<VarDecl>(ExtendingDecl)->getStorageDuration();
|
||||
}
|
||||
|
||||
|
|
|
@ -184,9 +184,8 @@ private:
|
|||
ManglingNumber(0), VariableOrMember(Member) { }
|
||||
|
||||
/// \brief Create the initialization entity for a binding.
|
||||
InitializedEntity(BindingDecl *Binding, QualType Type,
|
||||
const InitializedEntity &Parent)
|
||||
: Kind(EK_Binding), Parent(&Parent), Type(Type),
|
||||
InitializedEntity(BindingDecl *Binding, QualType Type)
|
||||
: Kind(EK_Binding), Parent(nullptr), Type(Type),
|
||||
ManglingNumber(0), VariableOrMember(Binding) {}
|
||||
|
||||
/// \brief Create the initialization entity for an array element.
|
||||
|
@ -324,10 +323,9 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Create the initialization entity for a structured binding.
|
||||
static InitializedEntity InitializeBinding(const InitializedEntity &Parent,
|
||||
BindingDecl *Binding,
|
||||
static InitializedEntity InitializeBinding(BindingDecl *Binding,
|
||||
QualType Type) {
|
||||
return InitializedEntity(Binding, Type, Parent);
|
||||
return InitializedEntity(Binding, Type);
|
||||
}
|
||||
|
||||
/// \brief Create the initialization entity for a lambda capture.
|
||||
|
|
|
@ -1728,9 +1728,8 @@ public:
|
|||
// Returns true if the variable declaration is a redeclaration
|
||||
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
|
||||
void CheckVariableDeclarationType(VarDecl *NewVD);
|
||||
void CheckCompleteVariableDeclaration(VarDecl *VD, InitializedEntity &Entity);
|
||||
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD,
|
||||
InitializedEntity &Entity);
|
||||
void CheckCompleteVariableDeclaration(VarDecl *VD);
|
||||
void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD);
|
||||
void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
|
||||
|
||||
NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
|
|
|
@ -433,7 +433,8 @@ namespace clang {
|
|||
Decl *VisitFunctionDecl(FunctionDecl *D,
|
||||
TemplateParameterList *TemplateParams);
|
||||
Decl *VisitDecl(Decl *D);
|
||||
Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate);
|
||||
Decl *VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate,
|
||||
ArrayRef<BindingDecl *> *Bindings = nullptr);
|
||||
|
||||
// Enable late instantiation of attributes. Late instantiated attributes
|
||||
// will be stored in LA.
|
||||
|
|
|
@ -811,8 +811,7 @@ void Sema::ActOnEndOfTranslationUnit() {
|
|||
VD->setInvalidDecl();
|
||||
|
||||
// No initialization is performed for a tentative definition.
|
||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
|
||||
CheckCompleteVariableDeclaration(VD, Entity);
|
||||
CheckCompleteVariableDeclaration(VD);
|
||||
|
||||
// Notify the consumer that we've completed a tentative definition.
|
||||
if (!VD->isInvalidDecl())
|
||||
|
|
|
@ -9720,8 +9720,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
|
||||
// Perform the initialization.
|
||||
ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
|
||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
||||
if (!VDecl->isInvalidDecl()) {
|
||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
||||
InitializationKind Kind =
|
||||
DirectInit
|
||||
? CXXDirectInit
|
||||
|
@ -9972,7 +9972,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
VDecl->setInitStyle(VarDecl::ListInit);
|
||||
}
|
||||
|
||||
CheckCompleteVariableDeclaration(VDecl, Entity);
|
||||
CheckCompleteVariableDeclaration(VDecl);
|
||||
}
|
||||
|
||||
/// ActOnInitializerError - Given that there was an error parsing an
|
||||
|
@ -10257,7 +10257,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
|
|||
Var->setInitStyle(VarDecl::CallInit);
|
||||
}
|
||||
|
||||
CheckCompleteVariableDeclaration(Var, Entity);
|
||||
CheckCompleteVariableDeclaration(Var);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10334,8 +10334,7 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
|
|||
AttrEnd.isValid() ? AttrEnd : IdentLoc);
|
||||
}
|
||||
|
||||
void Sema::CheckCompleteVariableDeclaration(VarDecl *var,
|
||||
InitializedEntity &Entity) {
|
||||
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
||||
if (var->isInvalidDecl()) return;
|
||||
|
||||
if (getLangOpts().OpenCL) {
|
||||
|
@ -10445,7 +10444,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var,
|
|||
if (!getLangOpts().CPlusPlus) return;
|
||||
|
||||
if (auto *DD = dyn_cast<DecompositionDecl>(var))
|
||||
CheckCompleteDecompositionDeclaration(DD, Entity);
|
||||
CheckCompleteDecompositionDeclaration(DD);
|
||||
|
||||
QualType type = var->getType();
|
||||
if (type->isDependentType()) return;
|
||||
|
|
|
@ -1065,10 +1065,10 @@ struct BindingDiagnosticTrap {
|
|||
};
|
||||
}
|
||||
|
||||
static bool
|
||||
checkTupleLikeDecomposition(Sema &S, ArrayRef<BindingDecl *> Bindings,
|
||||
ValueDecl *Src, InitializedEntity &ParentEntity,
|
||||
QualType DecompType, llvm::APSInt TupleSize) {
|
||||
static bool checkTupleLikeDecomposition(Sema &S,
|
||||
ArrayRef<BindingDecl *> Bindings,
|
||||
ValueDecl *Src, QualType DecompType,
|
||||
llvm::APSInt TupleSize) {
|
||||
if ((int64_t)Bindings.size() != TupleSize) {
|
||||
S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
|
||||
<< DecompType << (unsigned)Bindings.size() << TupleSize.toString(10)
|
||||
|
@ -1152,8 +1152,7 @@ checkTupleLikeDecomposition(Sema &S, ArrayRef<BindingDecl *> Bindings,
|
|||
if (RefType.isNull())
|
||||
return true;
|
||||
|
||||
InitializedEntity Entity =
|
||||
InitializedEntity::InitializeBinding(ParentEntity, B, RefType);
|
||||
InitializedEntity Entity = InitializedEntity::InitializeBinding(B, RefType);
|
||||
InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc);
|
||||
InitializationSequence Seq(S, Entity, Kind, Init);
|
||||
E = Seq.Perform(S, Entity, Kind, Init);
|
||||
|
@ -1341,8 +1340,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
|
|||
return false;
|
||||
}
|
||||
|
||||
void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD,
|
||||
InitializedEntity &Entity) {
|
||||
void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) {
|
||||
QualType DecompType = DD->getType();
|
||||
|
||||
// If the type of the decomposition is dependent, then so is the type of
|
||||
|
@ -1386,8 +1384,7 @@ void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD,
|
|||
return;
|
||||
|
||||
case IsTupleLike::TupleLike:
|
||||
if (checkTupleLikeDecomposition(*this, Bindings, DD, Entity, DecompType,
|
||||
TupleSize))
|
||||
if (checkTupleLikeDecomposition(*this, Bindings, DD, DecompType, TupleSize))
|
||||
DD->setInvalidDecl();
|
||||
return;
|
||||
|
||||
|
|
|
@ -5886,7 +5886,9 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
|
|||
return Entity;
|
||||
|
||||
case InitializedEntity::EK_Binding:
|
||||
return getEntityForTemporaryLifetimeExtension(Entity->getParent(), nullptr);
|
||||
// Per [dcl.decomp]p3, the binding is treated as a variable of reference
|
||||
// type.
|
||||
return Entity;
|
||||
|
||||
case InitializedEntity::EK_Parameter:
|
||||
case InitializedEntity::EK_Parameter_CF_Audited:
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/Sema/Initialization.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/PrettyDeclStackTrace.h"
|
||||
#include "clang/Sema/Template.h"
|
||||
|
@ -599,13 +600,27 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
|
|||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) {
|
||||
return BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(),
|
||||
D->getIdentifier());
|
||||
auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(),
|
||||
D->getIdentifier());
|
||||
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD);
|
||||
return NewBD;
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) {
|
||||
// FIXME: Instantiate bindings and pass them in.
|
||||
return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false);
|
||||
// Transform the bindings first.
|
||||
SmallVector<BindingDecl*, 16> NewBindings;
|
||||
for (auto *OldBD : D->bindings())
|
||||
NewBindings.push_back(cast<BindingDecl>(VisitBindingDecl(OldBD)));
|
||||
ArrayRef<BindingDecl*> NewBindingArray = NewBindings;
|
||||
|
||||
auto *NewDD = cast_or_null<DecompositionDecl>(
|
||||
VisitVarDecl(D, /*InstantiatingVarTemplate=*/false, &NewBindingArray));
|
||||
|
||||
if (!NewDD || NewDD->isInvalidDecl())
|
||||
for (auto *NewBD : NewBindings)
|
||||
NewBD->setInvalidDecl();
|
||||
|
||||
return NewDD;
|
||||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
||||
|
@ -613,7 +628,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
|
|||
}
|
||||
|
||||
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
|
||||
bool InstantiatingVarTemplate) {
|
||||
bool InstantiatingVarTemplate,
|
||||
ArrayRef<BindingDecl*> *Bindings) {
|
||||
|
||||
// Do substitution on the type of the declaration
|
||||
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
|
||||
|
@ -634,9 +650,15 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
|
|||
SemaRef.adjustContextForLocalExternDecl(DC);
|
||||
|
||||
// Build the instantiated declaration.
|
||||
VarDecl *Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
|
||||
D->getLocation(), D->getIdentifier(),
|
||||
DI->getType(), DI, D->getStorageClass());
|
||||
VarDecl *Var;
|
||||
if (Bindings)
|
||||
Var = DecompositionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
|
||||
D->getLocation(), DI->getType(), DI,
|
||||
D->getStorageClass(), *Bindings);
|
||||
else
|
||||
Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
|
||||
D->getLocation(), D->getIdentifier(), DI->getType(),
|
||||
DI, D->getStorageClass());
|
||||
|
||||
// In ARC, infer 'retaining' for variables of retainable type.
|
||||
if (SemaRef.getLangOpts().ObjCAutoRefCount &&
|
||||
|
|
|
@ -38,6 +38,5 @@ constexpr bool g(S &&s) {
|
|||
static_assert(g({1, 2}));
|
||||
|
||||
// FIXME: by-value array copies
|
||||
// FIXME: template instantiation
|
||||
// FIXME: ast file support
|
||||
// FIXME: code generation
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: %clang_cc1 -std=c++1z -verify %s
|
||||
|
||||
struct A { int x, y; };
|
||||
typedef int B[2];
|
||||
struct C { template<int> int get(); };
|
||||
struct D { int x, y, z; };
|
||||
struct E { int *p, n; };
|
||||
|
||||
namespace std {
|
||||
using size_t = decltype(sizeof(0));
|
||||
template<typename> struct tuple_size;
|
||||
template<size_t, typename> struct tuple_element { using type = int; };
|
||||
}
|
||||
|
||||
template<> struct std::tuple_size<C> { enum { value = 2 }; };
|
||||
|
||||
template<typename T> int decomp(T &t) {
|
||||
auto &[a, b] = t; // expected-error {{type 'D' decomposes into 3 elements, but only 2 names were provided}}
|
||||
return a + b; // expected-error {{cannot initialize return object of type 'int' with an rvalue of type 'int *'}}
|
||||
}
|
||||
|
||||
void test() {
|
||||
A a;
|
||||
B b;
|
||||
C c;
|
||||
D d;
|
||||
E e;
|
||||
decomp(a);
|
||||
decomp(b);
|
||||
decomp(c);
|
||||
decomp(d); // expected-note {{in instantiation of}}
|
||||
decomp(e); // expected-note {{in instantiation of}}
|
||||
}
|
Loading…
Reference in New Issue