summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/AST/ASTDumper.cpp8
-rw-r--r--clang/lib/AST/Decl.cpp6
-rw-r--r--clang/lib/AST/DeclCXX.cpp12
-rw-r--r--clang/lib/AST/Expr.cpp13
-rw-r--r--clang/lib/AST/ExprClassification.cpp1
-rw-r--r--clang/lib/Sema/Sema.cpp5
-rw-r--r--clang/lib/Sema/SemaDecl.cpp187
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp748
-rw-r--r--clang/lib/Sema/SemaExpr.cpp18
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp53
-rw-r--r--clang/lib/Sema/SemaInit.cpp21
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp7
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp40
-rw-r--r--clang/lib/Sema/SemaType.cpp11
14 files changed, 905 insertions, 225 deletions
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 1a4207f5120..55f9309f66e 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -429,6 +429,7 @@ namespace {
void VisitFieldDecl(const FieldDecl *D);
void VisitVarDecl(const VarDecl *D);
void VisitDecompositionDecl(const DecompositionDecl *D);
+ void VisitBindingDecl(const BindingDecl *D);
void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);
void VisitImportDecl(const ImportDecl *D);
void VisitPragmaCommentDecl(const PragmaCommentDecl *D);
@@ -1224,6 +1225,13 @@ void ASTDumper::VisitDecompositionDecl(const DecompositionDecl *D) {
dumpDecl(B);
}
+void ASTDumper::VisitBindingDecl(const BindingDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (auto *E = D->getBinding())
+ dumpStmt(E);
+}
+
void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
dumpStmt(D->getAsmString());
}
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 813a20a9f52..4486cb89404 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1395,6 +1395,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
return clang::LinkageComputer::getLVForDecl(D, computation);
}
+void NamedDecl::printName(raw_ostream &os) const {
+ os << Name;
+}
+
std::string NamedDecl::getQualifiedNameAsString() const {
std::string QualName;
llvm::raw_string_ostream OS(QualName);
@@ -1481,7 +1485,7 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
OS << "::";
}
- if (getDeclName())
+ if (getDeclName() || isa<DecompositionDecl>(this))
OS << *this;
else
OS << "(anonymous)";
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 7e6c7253483..14df382697e 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -2344,6 +2344,18 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C,
return Result;
}
+void DecompositionDecl::printName(llvm::raw_ostream &os) const {
+ os << '[';
+ bool Comma = false;
+ for (auto *B : bindings()) {
+ if (Comma)
+ os << ", ";
+ B->printName(os);
+ Comma = true;
+ }
+ os << ']';
+}
+
MSPropertyDecl *MSPropertyDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, DeclarationName N,
QualType T, TypeSourceInfo *TInfo,
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index e835686a1a9..15386aeec9d 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -3308,11 +3308,16 @@ FieldDecl *Expr::getSourceBitField() {
if (Ivar->isBitField())
return Ivar;
- if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E))
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) {
if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl()))
if (Field->isBitField())
return Field;
+ if (BindingDecl *BD = dyn_cast<BindingDecl>(DeclRef->getDecl()))
+ if (Expr *E = BD->getBinding())
+ return E->getSourceBitField();
+ }
+
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) {
if (BinOp->isAssignmentOp() && BinOp->getLHS())
return BinOp->getLHS()->getSourceBitField();
@@ -3329,6 +3334,7 @@ FieldDecl *Expr::getSourceBitField() {
}
bool Expr::refersToVectorElement() const {
+ // FIXME: Why do we not just look at the ObjectKind here?
const Expr *E = this->IgnoreParens();
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
@@ -3345,6 +3351,11 @@ bool Expr::refersToVectorElement() const {
if (isa<ExtVectorElementExpr>(E))
return true;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl()))
+ if (auto *E = BD->getBinding())
+ return E->refersToVectorElement();
+
return false;
}
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 89cc9bc18ef..8388013d668 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -429,6 +429,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
else
islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
isa<IndirectFieldDecl>(D) ||
+ isa<BindingDecl>(D) ||
(Ctx.getLangOpts().CPlusPlus &&
(isa<FunctionDecl>(D) || isa<MSPropertyDecl>(D) ||
isa<FunctionTemplateDecl>(D)));
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index eb5e5fec707..a57f1903576 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -28,6 +28,7 @@
#include "clang/Sema/CXXFieldCollector.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/MultiplexExternalSemaSource.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/PrettyDeclStackTrace.h"
@@ -809,7 +810,9 @@ void Sema::ActOnEndOfTranslationUnit() {
diag::err_tentative_def_incomplete_type))
VD->setInvalidDecl();
- CheckCompleteVariableDeclaration(VD);
+ // No initialization is performed for a tentative definition.
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
+ CheckCompleteVariableDeclaration(VD, Entity);
// Notify the consumer that we've completed a tentative definition.
if (!VD->isInvalidDecl())
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e850c3c3847..4a68d60a1e2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -43,7 +43,6 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
#include <cstring>
@@ -6534,157 +6533,6 @@ NamedDecl *Sema::ActOnVariableDeclarator(
return NewVD;
}
-NamedDecl *
-Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
- MultiTemplateParamsArg TemplateParamLists) {
- assert(D.isDecompositionDeclarator());
- const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator();
-
- // The syntax only allows a decomposition declarator as a simple-declaration
- // or a for-range-declaration, but we parse it in more cases than that.
- if (!D.mayHaveDecompositionDeclarator()) {
- Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)
- << Decomp.getSourceRange();
- return nullptr;
- }
-
- if (!TemplateParamLists.empty()) {
- // FIXME: There's no rule against this, but there are also no rules that
- // would actually make it usable, so we reject it for now.
- Diag(TemplateParamLists.front()->getTemplateLoc(),
- diag::err_decomp_decl_template);
- return nullptr;
- }
-
- Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z
- ? diag::warn_cxx14_compat_decomp_decl
- : diag::ext_decomp_decl)
- << Decomp.getSourceRange();
-
- // The semantic context is always just the current context.
- DeclContext *const DC = CurContext;
-
- // C++1z [dcl.dcl]/8:
- // The decl-specifier-seq shall contain only the type-specifier auto
- // and cv-qualifiers.
- auto &DS = D.getDeclSpec();
- {
- SmallVector<StringRef, 8> BadSpecifiers;
- SmallVector<SourceLocation, 8> BadSpecifierLocs;
- if (auto SCS = DS.getStorageClassSpec()) {
- BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS));
- BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc());
- }
- if (auto TSCS = DS.getThreadStorageClassSpec()) {
- BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS));
- BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
- }
- if (DS.isConstexprSpecified()) {
- BadSpecifiers.push_back("constexpr");
- BadSpecifierLocs.push_back(DS.getConstexprSpecLoc());
- }
- if (DS.isInlineSpecified()) {
- BadSpecifiers.push_back("inline");
- BadSpecifierLocs.push_back(DS.getInlineSpecLoc());
- }
- if (!BadSpecifiers.empty()) {
- auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);
- Err << (int)BadSpecifiers.size()
- << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " ");
- // Don't add FixItHints to remove the specifiers; we do still respect
- // them when building the underlying variable.
- for (auto Loc : BadSpecifierLocs)
- Err << SourceRange(Loc, Loc);
- }
- // We can't recover from it being declared as a typedef.
- if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
- return nullptr;
- }
-
- TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
- QualType R = TInfo->getType();
-
- if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
- UPPC_DeclarationType))
- D.setInvalidType();
-
- // The syntax only allows a single ref-qualifier prior to the decomposition
- // declarator. No other declarator chunks are permitted. Also check the type
- // specifier here.
- if (DS.getTypeSpecType() != DeclSpec::TST_auto ||
- D.hasGroupingParens() || D.getNumTypeObjects() > 1 ||
- (D.getNumTypeObjects() == 1 &&
- D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) {
- Diag(Decomp.getLSquareLoc(),
- (D.hasGroupingParens() ||
- (D.getNumTypeObjects() &&
- D.getTypeObject(0).Kind == DeclaratorChunk::Paren))
- ? diag::err_decomp_decl_parens
- : diag::err_decomp_decl_type)
- << R;
-
- // In most cases, there's no actual problem with an explicitly-specified
- // type, but a function type won't work here, and ActOnVariableDeclarator
- // shouldn't be called for such a type.
- if (R->isFunctionType())
- D.setInvalidType();
- }
-
- // Build the BindingDecls.
- SmallVector<BindingDecl*, 8> Bindings;
-
- // Build the BindingDecls.
- for (auto &B : D.getDecompositionDeclarator().bindings()) {
- // Check for name conflicts.
- DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
- LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
- ForRedeclaration);
- LookupName(Previous, S,
- /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit());
-
- // It's not permitted to shadow a template parameter name.
- if (Previous.isSingleResult() &&
- Previous.getFoundDecl()->isTemplateParameter()) {
- DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
- Previous.getFoundDecl());
- Previous.clear();
- }
-
- bool ConsiderLinkage = DC->isFunctionOrMethod() &&
- DS.getStorageClassSpec() == DeclSpec::SCS_extern;
- FilterLookupForScope(Previous, DC, S, ConsiderLinkage,
- /*AllowInlineNamespace*/false);
- if (!Previous.empty()) {
- auto *Old = Previous.getRepresentativeDecl();
- Diag(B.NameLoc, diag::err_redefinition) << B.Name;
- Diag(Old->getLocation(), diag::note_previous_definition);
- }
-
- auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);
- PushOnScopeChains(BD, S, true);
- Bindings.push_back(BD);
- ParsingInitForAutoVars.insert(BD);
- }
-
- // There are no prior lookup results for the variable itself, because it
- // is unnamed.
- DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,
- Decomp.getLSquareLoc());
- LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
-
- // Build the variable that holds the non-decomposed object.
- bool AddToScope = true;
- NamedDecl *New =
- ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
- MultiTemplateParamsArg(), AddToScope, Bindings);
- CurContext->addHiddenDecl(New);
-
- if (isInOpenMPDeclareTargetContext())
- checkDeclIsAllowedInOpenMPTarget(nullptr, New);
-
- return New;
-}
-
/// Enum describing the %select options in diag::warn_decl_shadow.
enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field };
@@ -9604,6 +9452,9 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
assert((!VDecl || !VDecl->isInitCapture()) &&
"init captures are expected to be deduced prior to initialization");
+ // FIXME: Deduction for a decomposition declaration does weird things if the
+ // initializer is an array.
+
ArrayRef<Expr *> DeduceInits = Init;
if (DirectInit) {
if (auto *PL = dyn_cast<ParenListExpr>(Init))
@@ -9713,6 +9564,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
return;
}
+ // C++1z [dcl.dcl]p1 grammar implies that a parenthesized initializer is not
+ // permitted.
+ if (isa<DecompositionDecl>(VDecl) && DirectInit && isa<ParenListExpr>(Init))
+ Diag(VDecl->getLocation(), diag::err_decomp_decl_paren_init) << VDecl;
+
// C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) {
// Attempt typo correction early so that the type of the init expression can
@@ -9864,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
@@ -10116,7 +9972,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VDecl->setInitStyle(VarDecl::ListInit);
}
- CheckCompleteVariableDeclaration(VDecl);
+ CheckCompleteVariableDeclaration(VDecl, Entity);
}
/// ActOnInitializerError - Given that there was an error parsing an
@@ -10173,6 +10029,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
QualType Type = Var->getType();
+ // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory.
+ if (isa<DecompositionDecl>(RealDecl)) {
+ Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var;
+ Var->setInvalidDecl();
+ return;
+ }
+
// C++11 [dcl.spec.auto]p3
if (TypeMayContainAuto && Type->getContainedAutoType()) {
Diag(Var->getLocation(), diag::err_auto_var_requires_init)
@@ -10394,7 +10257,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
Var->setInitStyle(VarDecl::CallInit);
}
- CheckCompleteVariableDeclaration(Var);
+ CheckCompleteVariableDeclaration(Var, Entity);
}
}
@@ -10471,7 +10334,8 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
AttrEnd.isValid() ? AttrEnd : IdentLoc);
}
-void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
+void Sema::CheckCompleteVariableDeclaration(VarDecl *var,
+ InitializedEntity &Entity) {
if (var->isInvalidDecl()) return;
if (getLangOpts().OpenCL) {
@@ -10580,6 +10444,9 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) return;
+ if (auto *DD = dyn_cast<DecompositionDecl>(var))
+ CheckCompleteDecompositionDeclaration(DD, Entity);
+
QualType type = var->getType();
if (type->isDependentType()) return;
@@ -10680,9 +10547,13 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
if (!VD)
return;
- if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl))
- for (auto *BD : DD->bindings())
+ if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) {
+ for (auto *BD : DD->bindings()) {
+ if (ThisDecl->isInvalidDecl())
+ BD->setInvalidDecl();
FinalizeDeclaration(BD);
+ }
+ }
checkAttributesAfterMerging(*this, *VD);
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 3bcce07a3a5..fc593be15b1 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -39,6 +39,7 @@
#include "clang/Sema/Template.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include <map>
#include <set>
@@ -664,6 +665,753 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
return Invalid;
}
+NamedDecl *
+Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParamLists) {
+ assert(D.isDecompositionDeclarator());
+ const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator();
+
+ // The syntax only allows a decomposition declarator as a simple-declaration
+ // or a for-range-declaration, but we parse it in more cases than that.
+ if (!D.mayHaveDecompositionDeclarator()) {
+ Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)
+ << Decomp.getSourceRange();
+ return nullptr;
+ }
+
+ if (!TemplateParamLists.empty()) {
+ // FIXME: There's no rule against this, but there are also no rules that
+ // would actually make it usable, so we reject it for now.
+ Diag(TemplateParamLists.front()->getTemplateLoc(),
+ diag::err_decomp_decl_template);
+ return nullptr;
+ }
+
+ Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z
+ ? diag::warn_cxx14_compat_decomp_decl
+ : diag::ext_decomp_decl)
+ << Decomp.getSourceRange();
+
+ // The semantic context is always just the current context.
+ DeclContext *const DC = CurContext;
+
+ // C++1z [dcl.dcl]/8:
+ // The decl-specifier-seq shall contain only the type-specifier auto
+ // and cv-qualifiers.
+ auto &DS = D.getDeclSpec();
+ {
+ SmallVector<StringRef, 8> BadSpecifiers;
+ SmallVector<SourceLocation, 8> BadSpecifierLocs;
+ if (auto SCS = DS.getStorageClassSpec()) {
+ BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS));
+ BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc());
+ }
+ if (auto TSCS = DS.getThreadStorageClassSpec()) {
+ BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS));
+ BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
+ }
+ if (DS.isConstexprSpecified()) {
+ BadSpecifiers.push_back("constexpr");
+ BadSpecifierLocs.push_back(DS.getConstexprSpecLoc());
+ }
+ if (DS.isInlineSpecified()) {
+ BadSpecifiers.push_back("inline");
+ BadSpecifierLocs.push_back(DS.getInlineSpecLoc());
+ }
+ if (!BadSpecifiers.empty()) {
+ auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);
+ Err << (int)BadSpecifiers.size()
+ << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " ");
+ // Don't add FixItHints to remove the specifiers; we do still respect
+ // them when building the underlying variable.
+ for (auto Loc : BadSpecifierLocs)
+ Err << SourceRange(Loc, Loc);
+ }
+ // We can't recover from it being declared as a typedef.
+ if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
+ return nullptr;
+ }
+
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
+ QualType R = TInfo->getType();
+
+ if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
+ UPPC_DeclarationType))
+ D.setInvalidType();
+
+ // The syntax only allows a single ref-qualifier prior to the decomposition
+ // declarator. No other declarator chunks are permitted. Also check the type
+ // specifier here.
+ if (DS.getTypeSpecType() != DeclSpec::TST_auto ||
+ D.hasGroupingParens() || D.getNumTypeObjects() > 1 ||
+ (D.getNumTypeObjects() == 1 &&
+ D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) {
+ Diag(Decomp.getLSquareLoc(),
+ (D.hasGroupingParens() ||
+ (D.getNumTypeObjects() &&
+ D.getTypeObject(0).Kind == DeclaratorChunk::Paren))
+ ? diag::err_decomp_decl_parens
+ : diag::err_decomp_decl_type)
+ << R;
+
+ // In most cases, there's no actual problem with an explicitly-specified
+ // type, but a function type won't work here, and ActOnVariableDeclarator
+ // shouldn't be called for such a type.
+ if (R->isFunctionType())
+ D.setInvalidType();
+ }
+
+ // Build the BindingDecls.
+ SmallVector<BindingDecl*, 8> Bindings;
+
+ // Build the BindingDecls.
+ for (auto &B : D.getDecompositionDeclarator().bindings()) {
+ // Check for name conflicts.
+ DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+ ForRedeclaration);
+ LookupName(Previous, S,
+ /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit());
+
+ // It's not permitted to shadow a template parameter name.
+ if (Previous.isSingleResult() &&
+ Previous.getFoundDecl()->isTemplateParameter()) {
+ DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
+ Previous.getFoundDecl());
+ Previous.clear();
+ }
+
+ bool ConsiderLinkage = DC->isFunctionOrMethod() &&
+ DS.getStorageClassSpec() == DeclSpec::SCS_extern;
+ FilterLookupForScope(Previous, DC, S, ConsiderLinkage,
+ /*AllowInlineNamespace*/false);
+ if (!Previous.empty()) {
+ auto *Old = Previous.getRepresentativeDecl();
+ Diag(B.NameLoc, diag::err_redefinition) << B.Name;
+ Diag(Old->getLocation(), diag::note_previous_definition);
+ }
+
+ auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);
+ PushOnScopeChains(BD, S, true);
+ Bindings.push_back(BD);
+ ParsingInitForAutoVars.insert(BD);
+ }
+
+ // There are no prior lookup results for the variable itself, because it
+ // is unnamed.
+ DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,
+ Decomp.getLSquareLoc());
+ LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
+
+ // Build the variable that holds the non-decomposed object.
+ bool AddToScope = true;
+ NamedDecl *New =
+ ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
+ MultiTemplateParamsArg(), AddToScope, Bindings);
+ CurContext->addHiddenDecl(New);
+
+ if (isInOpenMPDeclareTargetContext())
+ checkDeclIsAllowedInOpenMPTarget(nullptr, New);
+
+ return New;
+}
+
+static bool checkSimpleDecomposition(
+ Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src,
+ QualType DecompType, llvm::APSInt NumElems, QualType ElemType,
+ llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) {
+ if ((int64_t)Bindings.size() != NumElems) {
+ S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
+ << DecompType << (unsigned)Bindings.size() << NumElems.toString(10)
+ << (NumElems < Bindings.size());
+ return true;
+ }
+
+ unsigned I = 0;
+ for (auto *B : Bindings) {
+ SourceLocation Loc = B->getLocation();
+ ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
+ if (E.isInvalid())
+ return true;
+ E = GetInit(Loc, E.get(), I++);
+ if (E.isInvalid())
+ return true;
+ B->setBinding(ElemType, E.get());
+ }
+
+ return false;
+}
+
+static bool checkArrayLikeDecomposition(Sema &S,
+ ArrayRef<BindingDecl *> Bindings,
+ ValueDecl *Src, QualType DecompType,
+ llvm::APSInt NumElems,
+ QualType ElemType) {
+ return checkSimpleDecomposition(
+ S, Bindings, Src, DecompType, NumElems, ElemType,
+ [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult {
+ ExprResult E = S.ActOnIntegerConstant(Loc, I);
+ if (E.isInvalid())
+ return ExprError();
+ return S.CreateBuiltinArraySubscriptExpr(Base, Loc, E.get(), Loc);
+ });
+}
+
+static bool checkArrayDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
+ ValueDecl *Src, QualType DecompType,
+ const ConstantArrayType *CAT) {
+ return checkArrayLikeDecomposition(S, Bindings, Src, DecompType,
+ llvm::APSInt(CAT->getSize()),
+ CAT->getElementType());
+}
+
+static bool checkVectorDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
+ ValueDecl *Src, QualType DecompType,
+ const VectorType *VT) {
+ return checkArrayLikeDecomposition(
+ S, Bindings, Src, DecompType, llvm::APSInt::get(VT->getNumElements()),
+ S.Context.getQualifiedType(VT->getElementType(),
+ DecompType.getQualifiers()));
+}
+
+static bool checkComplexDecomposition(Sema &S,
+ ArrayRef<BindingDecl *> Bindings,
+ ValueDecl *Src, QualType DecompType,
+ const ComplexType *CT) {
+ return checkSimpleDecomposition(
+ S, Bindings, Src, DecompType, llvm::APSInt::get(2),
+ S.Context.getQualifiedType(CT->getElementType(),
+ DecompType.getQualifiers()),
+ [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult {
+ return S.CreateBuiltinUnaryOp(Loc, I ? UO_Imag : UO_Real, Base);
+ });
+}
+
+static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy,
+ TemplateArgumentListInfo &Args) {
+ SmallString<128> SS;
+ llvm::raw_svector_ostream OS(SS);
+ bool First = true;
+ for (auto &Arg : Args.arguments()) {
+ if (!First)
+ OS << ", ";
+ Arg.getArgument().print(PrintingPolicy, OS);
+ First = false;
+ }
+ return OS.str();
+}
+
+static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup,
+ SourceLocation Loc, StringRef Trait,
+ TemplateArgumentListInfo &Args,
+ unsigned DiagID) {
+ auto DiagnoseMissing = [&] {
+ if (DiagID)
+ S.Diag(Loc, DiagID) << printTemplateArgs(S.Context.getPrintingPolicy(),
+ Args);
+ return true;
+ };
+
+ // FIXME: Factor out duplication with lookupPromiseType in SemaCoroutine.
+ NamespaceDecl *Std = S.getStdNamespace();
+ if (!Std)
+ return DiagnoseMissing();
+
+ // Look up the trait itself, within namespace std. We can diagnose various
+ // problems with this lookup even if we've been asked to not diagnose a
+ // missing specialization, because this can only fail if the user has been
+ // declaring their own names in namespace std or we don't support the
+ // standard library implementation in use.
+ LookupResult Result(S, &S.PP.getIdentifierTable().get(Trait),
+ Loc, Sema::LookupOrdinaryName);
+ if (!S.LookupQualifiedName(Result, Std))
+ return DiagnoseMissing();
+ if (Result.isAmbiguous())
+ return true;
+
+ ClassTemplateDecl *TraitTD = Result.getAsSingle<ClassTemplateDecl>();
+ if (!TraitTD) {
+ Result.suppressDiagnostics();
+ NamedDecl *Found = *Result.begin();
+ S.Diag(Loc, diag::err_std_type_trait_not_class_template) << Trait;
+ S.Diag(Found->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ // Build the template-id.
+ QualType TraitTy = S.CheckTemplateIdType(TemplateName(TraitTD), Loc, Args);
+ if (TraitTy.isNull())
+ return true;
+ if (!S.isCompleteType(Loc, TraitTy)) {
+ if (DiagID)
+ S.RequireCompleteType(
+ Loc, TraitTy, DiagID,
+ printTemplateArgs(S.Context.getPrintingPolicy(), Args));
+ return true;
+ }
+
+ CXXRecordDecl *RD = TraitTy->getAsCXXRecordDecl();
+ assert(RD && "specialization of class template is not a class?");
+
+ // Look up the member of the trait type.
+ S.LookupQualifiedName(TraitMemberLookup, RD);
+ return TraitMemberLookup.isAmbiguous();
+}
+
+static TemplateArgumentLoc
+getTrivialIntegralTemplateArgument(Sema &S, SourceLocation Loc, QualType T,
+ uint64_t I) {
+ TemplateArgument Arg(S.Context, S.Context.MakeIntValue(I, T), T);
+ return S.getTrivialTemplateArgumentLoc(Arg, T, Loc);
+}
+
+static TemplateArgumentLoc
+getTrivialTypeTemplateArgument(Sema &S, SourceLocation Loc, QualType T) {
+ return S.getTrivialTemplateArgumentLoc(TemplateArgument(T), QualType(), Loc);
+}
+
+namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; }
+
+static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
+ llvm::APSInt &Size) {
+ EnterExpressionEvaluationContext ContextRAII(S, Sema::ConstantEvaluated);
+
+ DeclarationName Value = S.PP.getIdentifierInfo("value");
+ LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName);
+
+ // Form template argument list for tuple_size<T>.
+ TemplateArgumentListInfo Args(Loc, Loc);
+ Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T));
+
+ // If there's no tuple_size specialization, it's not tuple-like.
+ if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0))
+ return IsTupleLike::NotTupleLike;
+
+ // FIXME: According to the standard, we're not supposed to diagnose if any
+ // of the steps below fail (or if lookup for ::value is ambiguous or otherwise
+ // results in an error), but this is subject to a pending CWG issue / NB
+ // comment, which says we do diagnose if tuple_size<T> is complete but
+ // tuple_size<T>::value is not an ICE.
+
+ struct ICEDiagnoser : Sema::VerifyICEDiagnoser {
+ LookupResult &R;
+ TemplateArgumentListInfo &Args;
+ ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args)
+ : R(R), Args(Args) {}
+ void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+ S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant)
+ << printTemplateArgs(S.Context.getPrintingPolicy(), Args);
+ }
+ } Diagnoser(R, Args);
+
+ if (R.empty()) {
+ Diagnoser.diagnoseNotICE(S, Loc, SourceRange());
+ return IsTupleLike::Error;
+ }
+
+ ExprResult E =
+ S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false);
+ if (E.isInvalid())
+ return IsTupleLike::Error;
+
+ E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser, false);
+ if (E.isInvalid())
+ return IsTupleLike::Error;
+
+ return IsTupleLike::TupleLike;
+}
+
+/// \return std::tuple_element<I, T>::type.
+static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc,
+ unsigned I, QualType T) {
+ // Form template argument list for tuple_element<I, T>.
+ TemplateArgumentListInfo Args(Loc, Loc);
+ Args.addArgument(
+ getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I));
+ Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T));
+
+ DeclarationName TypeDN = S.PP.getIdentifierInfo("type");
+ LookupResult R(S, TypeDN, Loc, Sema::LookupOrdinaryName);
+ if (lookupStdTypeTraitMember(
+ S, R, Loc, "tuple_element", Args,
+ diag::err_decomp_decl_std_tuple_element_not_specialized))
+ return QualType();
+
+ auto *TD = R.getAsSingle<TypeDecl>();
+ if (!TD) {
+ R.suppressDiagnostics();
+ S.Diag(Loc, diag::err_decomp_decl_std_tuple_element_not_specialized)
+ << printTemplateArgs(S.Context.getPrintingPolicy(), Args);
+ if (!R.empty())
+ S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at);
+ return QualType();
+ }
+
+ return S.Context.getTypeDeclType(TD);
+}
+
+namespace {
+struct BindingDiagnosticTrap {
+ Sema &S;
+ DiagnosticErrorTrap Trap;
+ BindingDecl *BD;
+
+ BindingDiagnosticTrap(Sema &S, BindingDecl *BD)
+ : S(S), Trap(S.Diags), BD(BD) {}
+ ~BindingDiagnosticTrap() {
+ if (Trap.hasErrorOccurred())
+ S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD;
+ }
+};
+}
+
+static bool
+checkTupleLikeDecomposition(Sema &S, ArrayRef<BindingDecl *> Bindings,
+ ValueDecl *Src, InitializedEntity &ParentEntity,
+ 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)
+ << (TupleSize < Bindings.size());
+ return true;
+ }
+
+ if (Bindings.empty())
+ return false;
+
+ DeclarationName GetDN = S.PP.getIdentifierInfo("get");
+
+ // [dcl.decomp]p3:
+ // The unqualified-id get is looked up in the scope of E by class member
+ // access lookup
+ LookupResult MemberGet(S, GetDN, Src->getLocation(), Sema::LookupMemberName);
+ bool UseMemberGet = false;
+ if (S.isCompleteType(Src->getLocation(), DecompType)) {
+ if (auto *RD = DecompType->getAsCXXRecordDecl())
+ S.LookupQualifiedName(MemberGet, RD);
+ if (MemberGet.isAmbiguous())
+ return true;
+ UseMemberGet = !MemberGet.empty();
+ S.FilterAcceptableTemplateNames(MemberGet);
+ }
+
+ unsigned I = 0;
+ for (auto *B : Bindings) {
+ BindingDiagnosticTrap Trap(S, B);
+ SourceLocation Loc = B->getLocation();
+
+ ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
+ if (E.isInvalid())
+ return true;
+
+ // e is an lvalue if the type of the entity is an lvalue reference and
+ // an xvalue otherwise
+ if (!Src->getType()->isLValueReferenceType())
+ E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), CK_NoOp,
+ E.get(), nullptr, VK_XValue);
+
+ TemplateArgumentListInfo Args(Loc, Loc);
+ Args.addArgument(
+ getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I));
+
+ if (UseMemberGet) {
+ // if [lookup of member get] finds at least one declaration, the
+ // initializer is e.get<i-1>().
+ E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, false,
+ CXXScopeSpec(), SourceLocation(), nullptr,
+ MemberGet, &Args, nullptr);
+ if (E.isInvalid())
+ return true;
+
+ E = S.ActOnCallExpr(nullptr, E.get(), Loc, None, Loc);
+ } else {
+ // Otherwise, the initializer is get<i-1>(e), where get is looked up
+ // in the associated namespaces.
+ Expr *Get = UnresolvedLookupExpr::Create(
+ S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
+ DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/true, &Args,
+ UnresolvedSetIterator(), UnresolvedSetIterator());
+
+ Expr *Arg = E.get();
+ E = S.ActOnCallExpr(nullptr, Get, Loc, Arg, Loc);
+ }
+ if (E.isInvalid())
+ return true;
+ Expr *Init = E.get();
+
+ // Given the type T designated by std::tuple_element<i - 1, E>::type,
+ QualType T = getTupleLikeElementType(S, Loc, I, DecompType);
+ if (T.isNull())
+ return true;
+
+ // each vi is a variable of type "reference to T" initialized with the
+ // initializer, where the reference is an lvalue reference if the
+ // initializer is an lvalue and an rvalue reference otherwise
+ QualType RefType =
+ S.BuildReferenceType(T, E.get()->isLValue(), Loc, B->getDeclName());
+ if (RefType.isNull())
+ return true;
+
+ InitializedEntity Entity =
+ InitializedEntity::InitializeBinding(ParentEntity, B, RefType);
+ InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc);
+ InitializationSequence Seq(S, Entity, Kind, Init);
+ E = Seq.Perform(S, Entity, Kind, Init);
+ if (E.isInvalid())
+ return true;
+
+ B->setBinding(T, E.get());
+ I++;
+ }
+
+ return false;
+}
+
+/// Find the base class to decompose in a built-in decomposition of a class type.
+/// This base class search is, unfortunately, not quite like any other that we
+/// perform anywhere else in C++.
+static const CXXRecordDecl *findDecomposableBaseClass(Sema &S,
+ SourceLocation Loc,
+ const CXXRecordDecl *RD,
+ CXXCastPath &BasePath) {
+ auto BaseHasFields = [](const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path) {
+ return Specifier->getType()->getAsCXXRecordDecl()->hasDirectFields();
+ };
+
+ const CXXRecordDecl *ClassWithFields = nullptr;
+ if (RD->hasDirectFields())
+ // [dcl.decomp]p4:
+ // Otherwise, all of E's non-static data members shall be public direct
+ // members of E ...
+ ClassWithFields = RD;
+ else {
+ // ... or of ...
+ CXXBasePaths Paths;
+ Paths.setOrigin(const_cast<CXXRecordDecl*>(RD));
+ if (!RD->lookupInBases(BaseHasFields, Paths)) {
+ // If no classes have fields, just decompose RD itself. (This will work
+ // if and only if zero bindings were provided.)
+ return RD;
+ }
+
+ CXXBasePath *BestPath = nullptr;
+ for (auto &P : Paths) {
+ if (!BestPath)
+ BestPath = &P;
+ else if (!S.Context.hasSameType(P.back().Base->getType(),
+ BestPath->back().Base->getType())) {
+ // ... the same ...
+ S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members)
+ << false << RD << BestPath->back().Base->getType()
+ << P.back().Base->getType();
+ return nullptr;
+ } else if (P.Access < BestPath->Access) {
+ BestPath = &P;
+ }
+ }
+
+ // ... unambiguous ...
+ QualType BaseType = BestPath->back().Base->getType();
+ if (Paths.isAmbiguous(S.Context.getCanonicalType(BaseType))) {
+ S.Diag(Loc, diag::err_decomp_decl_ambiguous_base)
+ << RD << BaseType << S.getAmbiguousPathsDisplayString(Paths);
+ return nullptr;
+ }
+
+ // ... public base class of E.
+ if (BestPath->Access != AS_public) {
+ S.Diag(Loc, diag::err_decomp_decl_non_public_base)
+ << RD << BaseType;
+ for (auto &BS : *BestPath) {
+ if (BS.Base->getAccessSpecifier() != AS_public) {
+ S.Diag(BS.Base->getLocStart(), diag::note_access_constrained_by_path)
+ << (BS.Base->getAccessSpecifier() == AS_protected)
+ << (BS.Base->getAccessSpecifierAsWritten() == AS_none);
+ break;
+ }
+ }
+ return nullptr;
+ }
+
+ ClassWithFields = BaseType->getAsCXXRecordDecl();
+ S.BuildBasePathArray(Paths, BasePath);
+ }
+
+ // The above search did not check whether the selected class itself has base
+ // classes with fields, so check that now.
+ CXXBasePaths Paths;
+ if (ClassWithFields->lookupInBases(BaseHasFields, Paths)) {
+ S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members)
+ << (ClassWithFields == RD) << RD << ClassWithFields
+ << Paths.front().back().Base->getType();
+ return nullptr;
+ }
+
+ return ClassWithFields;
+}
+
+static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
+ ValueDecl *Src, QualType DecompType,
+ const CXXRecordDecl *RD) {
+ CXXCastPath BasePath;
+ RD = findDecomposableBaseClass(S, Src->getLocation(), RD, BasePath);
+ if (!RD)
+ return true;
+ QualType BaseType = S.Context.getQualifiedType(S.Context.getRecordType(RD),
+ DecompType.getQualifiers());
+
+ auto DiagnoseBadNumberOfBindings = [&]() -> bool {
+ unsigned NumFields = std::distance(RD->field_begin(), RD->field_end());
+ assert(Bindings.size() != NumFields);
+ S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
+ << DecompType << (unsigned)Bindings.size() << NumFields
+ << (NumFields < Bindings.size());
+ return true;
+ };
+
+ // all of E's non-static data members shall be public [...] members,
+ // E shall not have an anonymous union member, ...
+ unsigned I = 0;
+ for (auto *FD : RD->fields()) {
+ if (FD->isUnnamedBitfield())
+ continue;
+
+ if (FD->isAnonymousStructOrUnion()) {
+ S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member)
+ << DecompType << FD->getType()->isUnionType();
+ S.Diag(FD->getLocation(), diag::note_declared_at);
+ return true;
+ }
+
+ // We have a real field to bind.
+ if (I >= Bindings.size())
+ return DiagnoseBadNumberOfBindings();
+ auto *B = Bindings[I++];
+
+ SourceLocation Loc = B->getLocation();
+ if (FD->getAccess() != AS_public) {
+ S.Diag(Loc, diag::err_decomp_decl_non_public_member) << FD << DecompType;
+
+ // Determine whether the access specifier was explicit.
+ bool Implicit = true;
+ for (const auto *D : RD->decls()) {
+ if (declaresSameEntity(D, FD))
+ break;
+ if (isa<AccessSpecDecl>(D)) {
+ Implicit = false;
+ break;
+ }
+ }
+
+ S.Diag(FD->getLocation(), diag::note_access_natural)
+ << (FD->getAccess() == AS_protected) << Implicit;
+ return true;
+ }
+
+ // Initialize the binding to Src.FD.
+ ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
+ if (E.isInvalid())
+ return true;
+ E = S.ImpCastExprToType(E.get(), BaseType, CK_UncheckedDerivedToBase,
+ VK_LValue, &BasePath);
+ if (E.isInvalid())
+ return true;
+ E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc,
+ CXXScopeSpec(), FD,
+ DeclAccessPair::make(FD, FD->getAccess()),
+ DeclarationNameInfo(FD->getDeclName(), Loc));
+ if (E.isInvalid())
+ return true;
+
+ // If the type of the member is T, the referenced type is cv T, where cv is
+ // the cv-qualification of the decomposition expression.
+ //
+ // FIXME: We resolve a defect here: if the field is mutable, we do not add
+ // 'const' to the type of the field.
+ Qualifiers Q = DecompType.getQualifiers();
+ if (FD->isMutable())
+ Q.removeConst();
+ B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get());
+ }
+
+ if (I != Bindings.size())
+ return DiagnoseBadNumberOfBindings();
+
+ return false;
+}
+
+void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD,
+ InitializedEntity &Entity) {
+ QualType DecompType = DD->getType();
+
+ // If the type of the decomposition is dependent, then so is the type of
+ // each binding.
+ if (DecompType->isDependentType()) {
+ for (auto *B : DD->bindings())
+ B->setType(Context.DependentTy);
+ return;
+ }
+
+ DecompType = DecompType.getNonReferenceType();
+ ArrayRef<BindingDecl*> Bindings = DD->bindings();
+
+ // C++1z [dcl.decomp]/2:
+ // If E is an array type [...]
+ // As an extension, we also support decomposition of built-in complex and
+ // vector types.
+ if (auto *CAT = Context.getAsConstantArrayType(DecompType)) {
+ if (checkArrayDecomposition(*this, Bindings, DD, DecompType, CAT))
+ DD->setInvalidDecl();
+ return;
+ }
+ if (auto *VT = DecompType->getAs<VectorType>()) {
+ if (checkVectorDecomposition(*this, Bindings, DD, DecompType, VT))
+ DD->setInvalidDecl();
+ return;
+ }
+ if (auto *CT = DecompType->getAs<ComplexType>()) {
+ if (checkComplexDecomposition(*this, Bindings, DD, DecompType, CT))
+ DD->setInvalidDecl();
+ return;
+ }
+
+ // C++1z [dcl.decomp]/3:
+ // if the expression std::tuple_size<E>::value is a well-formed integral
+ // constant expression, [...]
+ llvm::APSInt TupleSize(32);
+ switch (isTupleLike(*this, DD->getLocation(), DecompType, TupleSize)) {
+ case IsTupleLike::Error:
+ DD->setInvalidDecl();
+ return;
+
+ case IsTupleLike::TupleLike:
+ if (checkTupleLikeDecomposition(*this, Bindings, DD, Entity, DecompType,
+ TupleSize))
+ DD->setInvalidDecl();
+ return;
+
+ case IsTupleLike::NotTupleLike:
+ break;
+ }
+
+ // C++1z [dcl.dcl]/8:
+ // [E shall be of array or non-union class type]
+ CXXRecordDecl *RD = DecompType->getAsCXXRecordDecl();
+ if (!RD || RD->isUnion()) {
+ Diag(DD->getLocation(), diag::err_decomp_decl_unbindable_type)
+ << DD << !RD << DecompType;
+ DD->setInvalidDecl();
+ return;
+ }
+
+ // C++1z [dcl.decomp]/4:
+ // all of E's non-static data members shall be [...] direct members of
+ // E or of the same unambiguous public base class of E, ...
+ if (checkMemberDecomposition(*this, Bindings, DD, DecompType, RD))
+ DD->setInvalidDecl();
+}
+
/// \brief Merge the exception specifications of two variable declarations.
///
/// This is called when there's a redeclaration of a VarDecl. The function
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7ecf84a38d9..81b57cad5ec 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1788,6 +1788,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
E->setObjectKind(OK_BitField);
}
+ // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier
+ // designates a bit-field.
+ if (auto *BD = dyn_cast<BindingDecl>(D))
+ if (auto *BE = BD->getBinding())
+ E->setObjectKind(BE->getObjectKind());
+
return E;
}
@@ -2943,7 +2949,6 @@ ExprResult Sema::BuildDeclarationNameExpr(
case Decl::VarTemplateSpecialization:
case Decl::VarTemplatePartialSpecialization:
case Decl::Decomposition:
- case Decl::Binding:
case Decl::OMPCapturedExpr:
// In C, "extern void blah;" is valid and is an r-value.
if (!getLangOpts().CPlusPlus &&
@@ -2971,6 +2976,14 @@ ExprResult Sema::BuildDeclarationNameExpr(
break;
}
+
+ case Decl::Binding: {
+ // These are always lvalues.
+ valueKind = VK_LValue;
+ type = type.getNonReferenceType();
+ // FIXME: Adjust cv-qualifiers for capture.
+ break;
+ }
case Decl::Function: {
if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
@@ -10580,7 +10593,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
return MPTy;
}
}
- } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl))
+ } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) &&
+ !isa<BindingDecl>(dcl))
llvm_unreachable("Unknown/unexpected decl type");
}
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 0c625b24c57..26f52bcd773 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -771,12 +771,6 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
false, ExtraArgs);
}
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- SourceLocation OpLoc, const CXXScopeSpec &SS,
- FieldDecl *Field, DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo);
-
ExprResult
Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
SourceLocation loc,
@@ -862,7 +856,7 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
// Make a nameInfo that properly uses the anonymous name.
DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
- result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
+ result = BuildFieldReferenceExpr(result, baseObjectIsPointer,
SourceLocation(), EmptySS, field,
foundDecl, memberNameInfo).get();
if (!result)
@@ -883,9 +877,10 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
DeclAccessPair::make(field, field->getAccess());
result =
- BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
- SourceLocation(), (FI == FEnd ? SS : EmptySS),
- field, fakeFoundDecl, memberNameInfo).get();
+ BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(),
+ (FI == FEnd ? SS : EmptySS), field,
+ fakeFoundDecl, memberNameInfo)
+ .get();
}
return result;
@@ -1153,8 +1148,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
return ExprError();
if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
- return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, OpLoc, SS, FD,
- FoundDecl, MemberNameInfo);
+ return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,
+ MemberNameInfo);
if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl))
return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,
@@ -1757,11 +1752,11 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base,
NameInfo, TemplateArgs, S, &ExtraArgs);
}
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
- SourceLocation OpLoc, const CXXScopeSpec &SS,
- FieldDecl *Field, DeclAccessPair FoundDecl,
- const DeclarationNameInfo &MemberNameInfo) {
+ExprResult
+Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
+ SourceLocation OpLoc, const CXXScopeSpec &SS,
+ FieldDecl *Field, DeclAccessPair FoundDecl,
+ const DeclarationNameInfo &MemberNameInfo) {
// x.a is an l-value if 'a' has a reference type. Otherwise:
// x.a is an l-value/x-value/pr-value if the base is (and note
// that *x is always an l-value), except that if the base isn't
@@ -1795,36 +1790,34 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
// except that 'mutable' members don't pick up 'const'.
if (Field->isMutable()) BaseQuals.removeConst();
- Qualifiers MemberQuals
- = S.Context.getCanonicalType(MemberType).getQualifiers();
+ Qualifiers MemberQuals =
+ Context.getCanonicalType(MemberType).getQualifiers();
assert(!MemberQuals.hasAddressSpace());
-
Qualifiers Combined = BaseQuals + MemberQuals;
if (Combined != MemberQuals)
- MemberType = S.Context.getQualifiedType(MemberType, Combined);
+ MemberType = Context.getQualifiedType(MemberType, Combined);
}
- S.UnusedPrivateFields.remove(Field);
+ UnusedPrivateFields.remove(Field);
- ExprResult Base =
- S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
- FoundDecl, Field);
+ ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
+ FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
MemberExpr *ME =
- BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,
+ BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
/*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
MemberNameInfo, MemberType, VK, OK);
// Build a reference to a private copy for non-static data members in
// non-static member functions, privatized by OpenMP constructs.
- if (S.getLangOpts().OpenMP && IsArrow &&
- !S.CurContext->isDependentContext() &&
+ if (getLangOpts().OpenMP && IsArrow &&
+ !CurContext->isDependentContext() &&
isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
- if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field))
- return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
+ if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field))
+ return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
}
return ME;
}
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index fc896941df0..6c156164bce 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -936,6 +936,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
case InitializedEntity::EK_BlockElement:
+ case InitializedEntity::EK_Binding:
llvm_unreachable("unexpected braced scalar init");
}
@@ -2895,6 +2896,7 @@ DeclarationName InitializedEntity::getName() const {
case EK_Variable:
case EK_Member:
+ case EK_Binding:
return VariableOrMember->getDeclName();
case EK_LambdaCapture:
@@ -2918,10 +2920,11 @@ DeclarationName InitializedEntity::getName() const {
llvm_unreachable("Invalid EntityKind!");
}
-DeclaratorDecl *InitializedEntity::getDecl() const {
+ValueDecl *InitializedEntity::getDecl() const {
switch (getKind()) {
case EK_Variable:
case EK_Member:
+ case EK_Binding:
return VariableOrMember;
case EK_Parameter:
@@ -2957,6 +2960,7 @@ bool InitializedEntity::allowsNRVO() const {
case EK_Parameter:
case EK_Parameter_CF_Audited:
case EK_Member:
+ case EK_Binding:
case EK_New:
case EK_Temporary:
case EK_CompoundLiteralInit:
@@ -2988,6 +2992,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
case EK_Result: OS << "Result"; break;
case EK_Exception: OS << "Exception"; break;
case EK_Member: OS << "Member"; break;
+ case EK_Binding: OS << "Binding"; break;
case EK_New: OS << "New"; break;
case EK_Temporary: OS << "Temporary"; break;
case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;
@@ -3004,9 +3009,9 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
break;
}
- if (Decl *D = getDecl()) {
+ if (auto *D = getDecl()) {
OS << " ";
- cast<NamedDecl>(D)->printQualifiedName(OS);
+ D->printQualifiedName(OS);
}
OS << " '" << getType().getAsString() << "'\n";
@@ -5270,6 +5275,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) {
return Sema::AA_Casting;
case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_Binding:
case InitializedEntity::EK_ArrayElement:
case InitializedEntity::EK_VectorElement:
case InitializedEntity::EK_ComplexElement:
@@ -5305,6 +5311,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
case InitializedEntity::EK_Parameter_CF_Audited:
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_RelatedResult:
+ case InitializedEntity::EK_Binding:
return true;
}
@@ -5326,6 +5333,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
return false;
case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_Binding:
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
@@ -5395,6 +5403,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
return Entity.getThrowLoc();
case InitializedEntity::EK_Variable:
+ case InitializedEntity::EK_Binding:
return Entity.getDecl()->getLocation();
case InitializedEntity::EK_LambdaCapture:
@@ -5826,6 +5835,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
case InitializedEntity::EK_Result:
case InitializedEntity::EK_Exception:
case InitializedEntity::EK_Member:
+ case InitializedEntity::EK_Binding:
case InitializedEntity::EK_New:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Delegating:
@@ -5875,6 +5885,9 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
// ctor-initializer persists until the constructor exits.
return Entity;
+ case InitializedEntity::EK_Binding:
+ return getEntityForTemporaryLifetimeExtension(Entity->getParent(), nullptr);
+
case InitializedEntity::EK_Parameter:
case InitializedEntity::EK_Parameter_CF_Audited:
// -- A temporary bound to a reference parameter in a function call
@@ -6250,7 +6263,7 @@ InitializationSequence::Perform(Sema &S,
SourceRange Brackets;
// Scavange the location of the brackets from the entity, if we can.
- if (DeclaratorDecl *DD = Entity.getDecl()) {
+ if (auto *DD = dyn_cast_or_null<DeclaratorDecl>(Entity.getDecl())) {
if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) {
TypeLoc TL = TInfo->getTypeLoc();
if (IncompleteArrayTypeLoc ArrayLoc =
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 99f92769744..a80b06f4e36 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2073,11 +2073,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
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));
+ SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
+ TA, ArgTy, TemplateArgs[2].getLocation()));
}
// The first template argument will be reused as the template decl that
// our synthetic template arguments will be applied to.
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 6fb3b53f91c..36c6877f67b 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2002,37 +2002,33 @@ static bool isSameTemplateArg(ASTContext &Context,
///
/// \param Loc The source location to use for the resulting template
/// argument.
-static TemplateArgumentLoc
-getTrivialTemplateArgumentLoc(Sema &S,
- const TemplateArgument &Arg,
- QualType NTTPType,
- SourceLocation Loc) {
+TemplateArgumentLoc
+Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
+ QualType NTTPType, SourceLocation Loc) {
switch (Arg.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't get a NULL template argument here");
case TemplateArgument::Type:
- return TemplateArgumentLoc(Arg,
- S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
+ return TemplateArgumentLoc(
+ Arg, Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
case TemplateArgument::Declaration: {
- Expr *E
- = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
- .getAs<Expr>();
+ Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ .getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
case TemplateArgument::NullPtr: {
- Expr *E
- = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
- .getAs<Expr>();
+ Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+ .getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true),
E);
}
case TemplateArgument::Integral: {
- Expr *E
- = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
+ Expr *E =
+ BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
return TemplateArgumentLoc(TemplateArgument(E), E);
}
@@ -2041,18 +2037,16 @@ getTrivialTemplateArgumentLoc(Sema &S,
NestedNameSpecifierLocBuilder Builder;
TemplateName Template = Arg.getAsTemplate();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
- Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc);
+ Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN =
Template.getAsQualifiedTemplateName())
- Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc);
+ Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
if (Arg.getKind() == TemplateArgument::Template)
- return TemplateArgumentLoc(Arg,
- Builder.getWithLocInContext(S.Context),
+ return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context),
Loc);
-
-
- return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.Context),
+
+ return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context),
Loc, Loc);
}
@@ -2100,7 +2094,7 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
// argument that we can check, almost as if the user had written
// the template argument explicitly.
TemplateArgumentLoc ArgLoc =
- getTrivialTemplateArgumentLoc(S, Arg, NTTPType, Info.getLocation());
+ S.getTrivialTemplateArgumentLoc(Arg, NTTPType, Info.getLocation());
// Check the template argument, converting it as necessary.
return S.CheckTemplateArgument(
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index f3747eaa5cb..091a4e34e19 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1748,6 +1748,12 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
if (T.isNull())
return QualType();
+ // Ignore any attempt to form a cv-qualified reference.
+ if (T->isReferenceType()) {
+ Qs.removeConst();
+ Qs.removeVolatile();
+ }
+
// Enforce C99 6.7.3p2: "Types other than pointer types derived from
// object or incomplete types shall not be restrict-qualified."
if (Qs.hasRestrict()) {
@@ -1789,6 +1795,11 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
if (T.isNull())
return QualType();
+ // Ignore any attempt to form a cv-qualified reference.
+ if (T->isReferenceType())
+ CVRAU &=
+ ~(DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic);
+
// Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and
// TQ_unaligned;
unsigned CVR = CVRAU & ~(DeclSpec::TQ_atomic | DeclSpec::TQ_unaligned);
OpenPOWER on IntegriCloud