diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ASTDumper.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/AST/Decl.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 12 | ||||
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/AST/ExprClassification.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 187 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 748 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 18 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprMember.cpp | 53 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 21 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 40 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 11 |
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); |

