r278435 - P0217R3: Perform semantic checks and initialization for the bindings in a

Reid Kleckner via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 16 08:02:40 PDT 2016


This p3.cpp test has been failing with MSVC 2013 since it was added:
http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9671

Relatedly, the cxx1z-decomposition.cpp test is failing at HEAD:
http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9744

I'll try to repro and get more info.

On Thu, Aug 11, 2016 at 3:25 PM, Richard Smith via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> 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 at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160816/7539c352/attachment-0001.html>


More information about the cfe-commits mailing list