Author: rsmith Date: Thu Aug 11 17:25:46 2016 New Revision: 278435 URL: http://llvm.org/viewvc/llvm-project?rev=278435&view=rev Log: P0217R3: Perform semantic checks and initialization for the bindings in a decomposition declaration for arrays, aggregate-like structs, tuple-like types, and (as an extension) for complex and vector types.
Added: cfe/trunk/test/CXX/dcl.decl/dcl.decomp/ cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp Modified: cfe/trunk/include/clang/AST/CXXInheritance.h cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/DeclCXX.h cfe/trunk/include/clang/AST/UnresolvedSet.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Sema/Initialization.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/ASTDumper.cpp cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/AST/Expr.cpp cfe/trunk/lib/AST/ExprClassification.cpp cfe/trunk/lib/Sema/Sema.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaExprMember.cpp cfe/trunk/lib/Sema/SemaInit.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/lib/Sema/SemaType.cpp cfe/trunk/test/Parser/cxx1z-decomposition.cpp cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Modified: cfe/trunk/include/clang/AST/CXXInheritance.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/CXXInheritance.h (original) +++ cfe/trunk/include/clang/AST/CXXInheritance.h Thu Aug 11 17:25:46 2016 @@ -172,7 +172,7 @@ public: /// paths for a derived-to-base search. explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true, bool DetectVirtual = true) - : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), + : Origin(), FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), DetectVirtual(DetectVirtual), DetectedVirtual(nullptr), NumDeclsFound(0) {} Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Thu Aug 11 17:25:46 2016 @@ -251,7 +251,7 @@ public: // FIXME: Deprecated, move clients to getName(). std::string getNameAsString() const { return Name.getAsString(); } - void printName(raw_ostream &os) const { os << Name; } + virtual void printName(raw_ostream &os) const; /// getDeclName - Get the actual, stored name of the declaration, /// which may be a special name. @@ -1025,7 +1025,7 @@ public: /// void foo() { int x; static int y; extern int z; } /// bool isLocalVarDecl() const { - if (getKind() != Decl::Var) + if (getKind() != Decl::Var && getKind() != Decl::Decomposition) return false; if (const DeclContext *DC = getLexicalDeclContext()) return DC->getRedeclContext()->isFunctionOrMethod(); @@ -1040,7 +1040,7 @@ public: /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but /// excludes variables declared in blocks. bool isFunctionOrMethodVarDecl() const { - if (getKind() != Decl::Var) + if (getKind() != Decl::Var && getKind() != Decl::Decomposition) return false; const DeclContext *DC = getLexicalDeclContext()->getRedeclContext(); return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block; Modified: cfe/trunk/include/clang/AST/DeclCXX.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h (original) +++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Aug 11 17:25:46 2016 @@ -1147,6 +1147,12 @@ public: /// \note This does NOT include a check for union-ness. bool isEmpty() const { return data().Empty; } + /// \brief Determine whether this class has direct non-static data members. + bool hasDirectFields() const { + auto &D = data(); + return D.HasPublicFields || D.HasProtectedFields || D.HasPrivateFields; + } + /// Whether this class is polymorphic (C++ [class.virtual]), /// which means that the class contains or inherits a virtual function. bool isPolymorphic() const { return data().Polymorphic; } @@ -3451,6 +3457,8 @@ public: return llvm::makeArrayRef(getTrailingObjects<BindingDecl *>(), NumBindings); } + void printName(raw_ostream &os) const override; + static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == Decomposition; } Modified: cfe/trunk/include/clang/AST/UnresolvedSet.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/UnresolvedSet.h?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/UnresolvedSet.h (original) +++ cfe/trunk/include/clang/AST/UnresolvedSet.h Thu Aug 11 17:25:46 2016 @@ -38,7 +38,7 @@ class UnresolvedSetIterator : public llv : iterator_adaptor_base(const_cast<DeclAccessPair *>(Iter)) {} public: - UnresolvedSetIterator() {} + UnresolvedSetIterator() = default; NamedDecl *getDecl() const { return I->getDecl(); } void setDecl(NamedDecl *ND) const { return I->setDecl(ND); } Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug 11 17:25:46 2016 @@ -385,6 +385,40 @@ def err_decomp_decl_template : Error< "decomposition declaration template not supported">; def err_decomp_decl_not_alone : Error< "decomposition declaration must be the only declaration in its group">; +def err_decomp_decl_requires_init : Error< + "decomposition declaration %0 requires an initializer">; +def err_decomp_decl_paren_init : Error< + "decomposition declaration %0 cannot have a parenthesized initializer">; +def err_decomp_decl_wrong_number_bindings : Error< + "type %0 decomposes into %2 elements, but %select{only |}3%1 " + "names were provided">; +def err_decomp_decl_unbindable_type : Error< + "cannot decompose %select{union|non-class, non-array}1 type %2">; +def err_decomp_decl_multiple_bases_with_members : Error< + "cannot decompose class type %1: " + "%select{its base classes %2 and|both it and its base class}0 %3 " + "have non-static data members">; +def err_decomp_decl_ambiguous_base : Error< + "cannot decompose members of ambiguous base class %1 of %0:%2">; +def err_decomp_decl_non_public_base : Error< + "cannot decompose members of non-public base class %1 of %0">; +def err_decomp_decl_non_public_member : Error< + "cannot decompose non-public member %0 of %1">; +def err_decomp_decl_anon_union_member : Error< + "cannot decompose class type %1 because it has an anonymous " + "%select{struct|union} member">; +def err_decomp_decl_std_tuple_element_not_specialized : Error< + "cannot decompose this type; 'std::tuple_element<%0>::type' " + "does not name a type">; +def err_decomp_decl_std_tuple_size_not_constant : Error< + "cannot decompose this type; 'std::tuple_size<%0>::value' " + "is not a valid integral constant expression">; +def note_in_binding_decl_init : Note< + "in implicit initialization of binding declaration %0">; + +def err_std_type_trait_not_class_template : Error< + "unsupported standard library implementation: " + "'std::%0' is not a class template">; // C++ using declarations def err_using_requires_qualname : Error< Modified: cfe/trunk/include/clang/Sema/Initialization.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Initialization.h (original) +++ cfe/trunk/include/clang/Sema/Initialization.h Thu Aug 11 17:25:46 2016 @@ -84,7 +84,10 @@ public: EK_RelatedResult, /// \brief The entity being initialized is a function parameter; function /// is member of group of audited CF APIs. - EK_Parameter_CF_Audited + EK_Parameter_CF_Audited, + /// \brief The entity being initialized is a structured binding of a + /// decomposition declaration. + EK_Binding, // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this // enum as an index for its first %select. When modifying this list, @@ -126,9 +129,9 @@ private: }; union { - /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or - /// FieldDecl, respectively. - DeclaratorDecl *VariableOrMember; + /// \brief When Kind == EK_Variable, EK_Member or EK_Binding, the VarDecl, + /// FieldDecl or BindingDecl, respectively. + ValueDecl *VariableOrMember; /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where /// result type was implicitly changed to accommodate ARC semantics. @@ -180,6 +183,12 @@ private: : Kind(EK_Member), Parent(Parent), Type(Member->getType()), ManglingNumber(0), VariableOrMember(Member) { } + /// \brief Create the initialization entity for a binding. + InitializedEntity(BindingDecl *Binding, QualType Type, + const InitializedEntity &Parent) + : Kind(EK_Binding), Parent(&Parent), Type(Type), + ManglingNumber(0), VariableOrMember(Binding) {} + /// \brief Create the initialization entity for an array element. InitializedEntity(ASTContext &Context, unsigned Index, const InitializedEntity &Parent); @@ -314,6 +323,13 @@ public: return InitializedEntity(Context, Index, Parent); } + /// \brief Create the initialization entity for a structured binding. + static InitializedEntity InitializeBinding(const InitializedEntity &Parent, + BindingDecl *Binding, + QualType Type) { + return InitializedEntity(Binding, Type, Parent); + } + /// \brief Create the initialization entity for a lambda capture. static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID, QualType FieldType, @@ -355,7 +371,7 @@ public: /// \brief Retrieve the variable, parameter, or field being /// initialized. - DeclaratorDecl *getDecl() const; + ValueDecl *getDecl() const; /// \brief Retrieve the ObjectiveC method being initialized. ObjCMethodDecl *getMethodDecl() const { return MethodDecl; } Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Aug 11 17:25:46 2016 @@ -1728,7 +1728,9 @@ public: // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckVariableDeclarationType(VarDecl *NewVD); - void CheckCompleteVariableDeclaration(VarDecl *var); + void CheckCompleteVariableDeclaration(VarDecl *VD, InitializedEntity &Entity); + void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD, + InitializedEntity &Entity); void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, @@ -3970,6 +3972,12 @@ public: bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); + ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, + SourceLocation OpLoc, + const CXXScopeSpec &SS, FieldDecl *Field, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo); + ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, @@ -5772,6 +5780,10 @@ public: TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody = nullptr); + TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, + QualType NTTPType, + SourceLocation Loc); + void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); Modified: cfe/trunk/lib/AST/ASTDumper.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTDumper.cpp (original) +++ cfe/trunk/lib/AST/ASTDumper.cpp Thu Aug 11 17:25:46 2016 @@ -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(c 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()); } Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Thu Aug 11 17:25:46 2016 @@ -1395,6 +1395,10 @@ static LinkageInfo getLVForDecl(const Na 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_o OS << "::"; } - if (getDeclName()) + if (getDeclName() || isa<DecompositionDecl>(this)) OS << *this; else OS << "(anonymous)"; Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Aug 11 17:25:46 2016 @@ -2344,6 +2344,18 @@ DecompositionDecl *DecompositionDecl::Cr 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, Modified: cfe/trunk/lib/AST/Expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/AST/Expr.cpp (original) +++ cfe/trunk/lib/AST/Expr.cpp Thu Aug 11 17:25:46 2016 @@ -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; } Modified: cfe/trunk/lib/AST/ExprClassification.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprClassification.cpp (original) +++ cfe/trunk/lib/AST/ExprClassification.cpp Thu Aug 11 17:25:46 2016 @@ -429,6 +429,7 @@ static Cl::Kinds ClassifyDecl(ASTContext 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))); Modified: cfe/trunk/lib/Sema/Sema.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/Sema.cpp (original) +++ cfe/trunk/lib/Sema/Sema.cpp Thu Aug 11 17:25:46 2016 @@ -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()) Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 11 17:25:46 2016 @@ -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::deduceVarTypeFromInitiali 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 *Re 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 *Re // 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 *Re 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 * 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 * Var->setInitStyle(VarDecl::CallInit); } - CheckCompleteVariableDeclaration(Var); + CheckCompleteVariableDeclaration(Var, Entity); } } @@ -10471,7 +10334,8 @@ Sema::ActOnCXXForRangeIdentifier(Scope * 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::CheckCompleteVariableDeclarat // 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); Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Aug 11 17:25:46 2016 @@ -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(Function 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 Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Aug 11 17:25:46 2016 @@ -1788,6 +1788,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, Qua 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::BuildDeclarationNameExp 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::BuildDeclarationNameExp 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(Exp 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"); } Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprMember.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprMember.cpp Thu Aug 11 17:25:46 2016 @@ -771,12 +771,6 @@ Sema::BuildMemberReferenceExpr(Expr *Bas 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::BuildAnonymousStructUnionMemberRef // 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::BuildAnonymousStructUnionMemberRef 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 *Bas 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(S 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 *B // 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; } Modified: cfe/trunk/lib/Sema/SemaInit.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp (original) +++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Aug 11 17:25:46 2016 @@ -936,6 +936,7 @@ static void warnBracedScalarInit(Sema &S 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::getNa case EK_Variable: case EK_Member: + case EK_Binding: return VariableOrMember->getDeclName(); case EK_LambdaCapture: @@ -2918,10 +2920,11 @@ DeclarationName InitializedEntity::getNa 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() con 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 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 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 InitializedEnt 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 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 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 getInitializationL return Entity.getThrowLoc(); case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Binding: return Entity.getDecl()->getLocation(); case InitializedEntity::EK_LambdaCapture: @@ -5826,6 +5835,7 @@ InitializedEntityOutlivesFullExpression( 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 *getEntit // 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 = Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Aug 11 17:25:46 2016 @@ -2073,11 +2073,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef 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. Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Aug 11 17:25:46 2016 @@ -2002,37 +2002,33 @@ static bool isSameTemplateArg(ASTContext /// /// \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, // 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( Modified: cfe/trunk/lib/Sema/SemaType.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaType.cpp (original) +++ cfe/trunk/lib/Sema/SemaType.cpp Thu Aug 11 17:25:46 2016 @@ -1748,6 +1748,12 @@ QualType Sema::BuildQualifiedType(QualTy 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(QualTy 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); Added: cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp?rev=278435&view=auto ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp (added) +++ cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp Thu Aug 11 17:25:46 2016 @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +int array() { + int arr[3] = {}; + // FIXME: We are supposed to create an array object here and perform elementwise initialization. + auto [a, b, c] = arr; // expected-error {{cannot decompose non-class, non-array}} + + auto &[d, e] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but only 2 names were provided}} + auto &[f, g, h, i] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but 4 names were provided}} + + auto &[r0, r1, r2] = arr; + const auto &[cr0, cr1, cr2] = arr; + + //static_assert(&arr[0] == &r0); + //static_assert(&arr[0] == &cr0); + using T = int; + using T = decltype(r0); + using U = const int; + using U = decltype(cr0); + + return r1 + cr2; +} Added: cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp?rev=278435&view=auto ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp (added) +++ cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp Thu Aug 11 17:25:46 2016 @@ -0,0 +1,203 @@ +// RUN: %clang_cc1 -std=c++1z -verify %s + +using size_t = decltype(sizeof(0)); + +struct A { int x, y; }; +struct B { int x, y; }; + +void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise + +namespace std { template<typename T> struct tuple_size; } +void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise + +struct Bad1 {}; +template<> struct std::tuple_size<Bad1> {}; +void no_tuple_size_3() { auto [x, y] = Bad1(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad1>::value' is not a valid integral constant expression}} + +struct Bad2 {}; +template<> struct std::tuple_size<Bad2> { const int value = 5; }; +void no_tuple_size_4() { auto [x, y] = Bad2(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad2>::value' is not a valid integral constant expression}} + +template<> struct std::tuple_size<A> { static const int value = 3; }; +template<> struct std::tuple_size<B> { enum { value = 3 }; }; + +void no_get_1() { + { + auto [a0, a1] = A(); // expected-error {{decomposes into 3 elements}} + auto [b0, b1] = B(); // expected-error {{decomposes into 3 elements}} + } + auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} +} + +int get(A); + +void no_get_2() { + // FIXME: This diagnostic is not great. + auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}} +} + +template<int> float &get(A); + +void no_tuple_element_1() { + auto [a0, a1, a2] = A(); // expected-error-re {{'std::tuple_element<0U{{L*}}, A>::type' does not name a type}} expected-note {{in implicit}} +} + +namespace std { template<size_t, typename> struct tuple_element; } // expected-note 2{{here}} + +void no_tuple_element_2() { + auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<0, A>'}} expected-note {{in implicit}} +} + +template<> struct std::tuple_element<0, A> { typedef float type; }; + +void no_tuple_element_3() { + auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<1, A>'}} expected-note {{in implicit}} +} + +template<> struct std::tuple_element<1, A> { typedef float &type; }; +template<> struct std::tuple_element<2, A> { typedef const float &type; }; + +template<int N> auto get(B) -> int (&)[N + 1]; +template<int N> struct std::tuple_element<N, B> { typedef int type[N +1 ]; }; + +template<typename T> struct std::tuple_size<const T> : std::tuple_size<T> {}; +template<size_t N, typename T> struct std::tuple_element<N, const T> { + typedef const typename std::tuple_element<N, T>::type type; +}; + +void referenced_type() { + auto [a0, a1, a2] = A(); + auto [b0, b1, b2] = B(); + + A a; + B b; + auto &[ar0, ar1, ar2] = a; + auto &[br0, br1, br2] = b; + + auto &&[arr0, arr1, arr2] = A(); + auto &&[brr0, brr1, brr2] = B(); + + const auto &[acr0, acr1, acr2] = A(); + const auto &[bcr0, bcr1, bcr2] = B(); + + + using Float = float; + using Float = decltype(a0); + using Float = decltype(ar0); + using Float = decltype(arr0); + + using ConstFloat = const float; + using ConstFloat = decltype(acr0); + + using FloatRef = float&; + using FloatRef = decltype(a1); + using FloatRef = decltype(ar1); + using FloatRef = decltype(arr1); + using FloatRef = decltype(acr1); + + using ConstFloatRef = const float&; + using ConstFloatRef = decltype(a2); + using ConstFloatRef = decltype(ar2); + using ConstFloatRef = decltype(arr2); + using ConstFloatRef = decltype(acr2); + + + using Int1 = int[1]; + using Int1 = decltype(b0); + using Int1 = decltype(br0); + using Int1 = decltype(brr0); + + using ConstInt1 = const int[1]; + using ConstInt1 = decltype(bcr0); + + using Int2 = int[2]; + using Int2 = decltype(b1); + using Int2 = decltype(br1); + using Int2 = decltype(brr1); + + using ConstInt2 = const int[2]; + using ConstInt2 = decltype(bcr1); + + using Int3 = int[3]; + using Int3 = decltype(b2); + using Int3 = decltype(br2); + using Int3 = decltype(brr2); + + using ConstInt3 = const int[3]; + using ConstInt3 = decltype(bcr2); +} + +struct C { template<int> int get(); }; +template<> struct std::tuple_size<C> { static const int value = 1; }; +template<> struct std::tuple_element<0, C> { typedef int type; }; + +int member_get() { + auto [c] = C(); + using T = int; + using T = decltype(c); + return c; +} + +struct D { template<int> struct get {}; }; // expected-note {{declared here}} +template<> struct std::tuple_size<D> { static const int value = 1; }; +template<> struct std::tuple_element<0, D> { typedef D::get<0> type; }; +void member_get_class_template() { + auto [d] = D(); // expected-error {{cannot refer to member 'get' in 'D' with '.'}} expected-note {{in implicit init}} +} + +struct E { int get(); }; +template<> struct std::tuple_size<E> { static const int value = 1; }; +template<> struct std::tuple_element<0, E> { typedef int type; }; +void member_get_non_template() { + // FIXME: This diagnostic is not very good. + auto [e] = E(); // expected-error {{no member named 'get'}} expected-note {{in implicit init}} +} + +namespace ADL { + struct X {}; +}; +template<int> int get(ADL::X); +template<> struct std::tuple_size<ADL::X> { static const int value = 1; }; +template<> struct std::tuple_element<0, ADL::X> { typedef int type; }; +void adl_only_bad() { + auto [x] = ADL::X(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit init}} +} + +template<typename ElemType, typename GetTypeLV, typename GetTypeRV> +struct wrap { + template<size_t> GetTypeLV get() &; + template<size_t> GetTypeRV get() &&; +}; +template<typename ET, typename GTL, typename GTR> +struct std::tuple_size<wrap<ET, GTL, GTR>> { + static const int value = 1; +}; +template<typename ET, typename GTL, typename GTR> +struct std::tuple_element<0, wrap<ET, GTL, GTR>> { + using type = ET; +}; + +template<typename T> T &lvalue(); + +void test_value_category() { + // If the declared variable is an lvalue reference, the operand to get is an + // lvalue. Otherwise it's an xvalue. + { auto [a] = wrap<int, void, int>(); } + { auto &[a] = lvalue<wrap<int, int, void>>(); } + { auto &&[a] = wrap<int, void, int>(); } + // If the initializer (call to get) is an lvalue, the binding is an lvalue + // reference to the element type. Otherwise it's an rvalue reference to the + // element type. + { auto [a] = wrap<int, void, int&>(); } + { auto [a] = wrap<int&, void, int&>(); } + { auto [a] = wrap<int&&, void, int&>(); } // ok, reference collapse to int& + + { auto [a] = wrap<int, void, int&&>(); } + { auto [a] = wrap<int&, void, int&&>(); } // expected-error {{non-const lvalue reference to type 'int' cannot bind}} expected-note {{in implicit}} + { auto [a] = wrap<const int&, void, int&&>(); } + { auto [a] = wrap<int&&, void, int&&>(); } + + { auto [a] = wrap<int, void, float&>(); } // expected-error {{cannot bind}} expected-note {{implicit}} + { auto [a] = wrap<const int, void, float&>(); } // ok, const int &a can bind to float + { auto [a] = wrap<int, void, float>(); } // ok, int &&a can bind to float +} Added: cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp?rev=278435&view=auto ============================================================================== --- cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp (added) +++ cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp Thu Aug 11 17:25:46 2016 @@ -0,0 +1,173 @@ +// RUN: %clang_cc1 -std=c++1z -verify -triple i686-linux-gnu %s + +template<typename T, typename U> struct same; +template<typename T> struct same<T, T> { ~same(); }; + +struct Empty {}; + +struct A { + int a; +}; + +namespace NonPublicMembers { + struct NonPublic1 { + protected: + int a; // expected-note {{declared protected here}} + }; + + struct NonPublic2 { + private: + int a; // expected-note 2{{declared private here}} + }; + + struct NonPublic3 : private A {}; // expected-note {{constrained by private inheritance}} + + struct NonPublic4 : NonPublic2 {}; + + void test() { + auto [a1] = NonPublic1(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic1'}} + auto [a2] = NonPublic2(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic2'}} + auto [a3] = NonPublic3(); // expected-error {{cannot decompose members of non-public base class 'A' of 'NonPublic3'}} + auto [a4] = NonPublic4(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic4'}} + } +} + +namespace MultipleClasses { + struct B : A { + int a; + }; + + struct C { int a; }; + struct D : A, C {}; + + struct E : virtual A {}; + struct F : A, E {}; // expected-warning {{direct base 'A' is inaccessible due to ambiguity}} + + struct G : virtual A {}; + struct H : E, G {}; + + struct I { int i; }; + struct J : I {}; + struct K : I, virtual J {}; // expected-warning {{direct base 'MultipleClasses::I' is inaccessible due to ambiguity}} + + struct L : virtual J {}; + struct M : virtual J, L {}; + + void test() { + auto [b] = B(); // expected-error {{cannot decompose class type 'B': both it and its base class 'A' have non-static data members}} + auto [d] = D(); // expected-error {{cannot decompose class type 'D': its base classes 'A' and 'MultipleClasses::C' have non-static data members}} + auto [e] = E(); + auto [f] = F(); // expected-error-re {{cannot decompose members of ambiguous base class 'A' of 'F':{{.*}}struct MultipleClasses::F -> struct A{{.*}}struct MultipleClasses::F -> struct MultipleClasses::E -> struct A}} + auto [h] = H(); // ok, only one (virtual) base subobject even though there are two paths to it + auto [k] = K(); // expected-error {{cannot decompose members of ambiguous base class 'MultipleClasses::I'}} + auto [m] = M(); // ok, all paths to I are through the same virtual base subobject J + + same<decltype(m), int>(); + } +} + +namespace BindingTypes { + struct A { + int i = 0; + int &r = i; + const float f = i; + mutable volatile int mvi; + }; + void e() { + auto [i,r,f,mvi] = A(); + + same<decltype(i), int>(); + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); + + same<decltype((i)), int&>(); + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); + } + void f() { + auto &&[i,r,f,mvi] = A(); + + same<decltype(i), int>(); + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); + + same<decltype((i)), int&>(); + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); + } + void g() { + const auto [i,r,f,mvi] = A(); + + same<decltype(i), const int>(); + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx + + same<decltype((i)), const int&>(); + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx + } + void h() { + typedef const A CA; + auto &[i,r,f,mvi] = CA(); // type of var is 'const A &' + + same<decltype(i), const int>(); // not 'int', per expected resolution of DRxxx + same<decltype(r), int&>(); + same<decltype(f), const float>(); + same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx + + same<decltype((i)), const int&>(); // not 'int&', per expected resolution of DRxxx + same<decltype((r)), int&>(); + same<decltype((f)), const float&>(); + same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx + } + struct B { + mutable int i; + }; + void mut() { + auto [i] = B(); + const auto [ci] = B(); + volatile auto [vi] = B(); + same<decltype(i), int>(); + same<decltype(ci), int>(); + same<decltype(vi), volatile int>(); + } +} + +namespace Bitfield { + struct S { unsigned long long x : 4, y : 32; int z; }; // expected-note 2{{here}} + int f(S s) { + auto [a, b, c] = s; + unsigned long long &ra = a; // expected-error {{bit-field 'x'}} + unsigned long long &rb = b; // expected-error {{bit-field 'y'}} + int &rc = c; + + // the type of the binding is the type of the field + same<decltype(a), unsigned long long>(); + same<decltype(b), unsigned long long>(); + + // the type of the expression is an lvalue of the field type + // (even though a reference can't bind to the field) + same<decltype((a)), unsigned long long&>(); + same<decltype((b)), unsigned long long&>(); + + // the expression promotes to a type large enough to hold the result + same<decltype(+a), int>(); + same<decltype(+b), unsigned int>(); + return rc; + } +} + +namespace std_example { + struct S { int x1 : 2; volatile double y1; }; + S f(); + const auto [x, y] = f(); + + same<decltype((x)), const int&> same1; + same<decltype((y)), const volatile double&> same2; +} Modified: cfe/trunk/test/Parser/cxx1z-decomposition.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/test/Parser/cxx1z-decomposition.cpp (original) +++ cfe/trunk/test/Parser/cxx1z-decomposition.cpp Thu Aug 11 17:25:46 2016 @@ -67,7 +67,7 @@ namespace BadSpecifiers { // storage-class-specifiers static auto &[a] = n; // expected-error {{cannot be declared 'static'}} thread_local auto &[b] = n; // expected-error {{cannot be declared 'thread_local'}} - extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} + extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}} struct S { mutable auto &[d] = n; // expected-error {{not permitted in this context}} @@ -97,7 +97,7 @@ namespace BadSpecifiers { auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}} // FIXME: This should fire the 'misplaced array declarator' diagnostic. - int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} + int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}} int [5] arr = {0}; // expected-error {{place the brackets after the name}} auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}} @@ -133,3 +133,16 @@ namespace Template { // FIXME: There's no actual rule against this... template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}} } + +namespace Init { + void f() { + int arr[1]; + struct S { int n; }; + auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}} + const auto &[bad2](S{}); // expected-error {{decomposition declaration '[bad2]' cannot have a parenthesized initializer}} + auto &[good1] = arr; + auto &&[good2] = S{}; + S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}} + S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}} + } +} Modified: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp (original) +++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Thu Aug 11 17:25:46 2016 @@ -4,7 +4,23 @@ void use_from_own_init() { auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}} } -// FIXME: create correct bindings +// As a Clang extension, _Complex can be decomposed. +float decompose_complex(_Complex float cf) { + auto [re, im] = cf; + //static_assert(&re == &__real cf); + //static_assert(&im == &__imag cf); + return re*re + im*im; +} + +// As a Clang extension, vector types can be decomposed. +typedef float vf3 __attribute__((ext_vector_type(3))); +float decompose_vector(vf3 v) { + auto [x, y, z] = v; + auto *p = &x; // expected-error {{address of vector element requested}} + return x + y + z; +} + +// FIXME: by-value array copies // FIXME: template instantiation // FIXME: ast file support // FIXME: code generation _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits