<div dir="ltr">This p3.cpp test has been failing with MSVC 2013 since it was added:<div><a href="http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9671">http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9671</a><br></div><div><br></div><div>Relatedly, the cxx1z-decomposition.cpp test is failing at HEAD:</div><div><a href="http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9744">http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9744</a><br></div><div><br></div><div>I'll try to repro and get more info.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Aug 11, 2016 at 3:25 PM, Richard Smith via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Thu Aug 11 17:25:46 2016<br>
New Revision: 278435<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=278435&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=278435&view=rev</a><br>
Log:<br>
P0217R3: Perform semantic checks and initialization for the bindings in a<br>
decomposition declaration for arrays, aggregate-like structs, tuple-like<br>
types, and (as an extension) for complex and vector types.<br>
<br>
Added:<br>
  cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/<br>
  cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p2.cpp<br>
  cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p3.cpp<br>
  cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p4.cpp<br>
Modified:<br>
  cfe/trunk/include/clang/AST/<wbr>CXXInheritance.h<br>
  cfe/trunk/include/clang/AST/<wbr>Decl.h<br>
  cfe/trunk/include/clang/AST/<wbr>DeclCXX.h<br>
  cfe/trunk/include/clang/AST/<wbr>UnresolvedSet.h<br>
  cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td<br>
  cfe/trunk/include/clang/Sema/<wbr>Initialization.h<br>
  cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
  cfe/trunk/lib/AST/ASTDumper.<wbr>cpp<br>
  cfe/trunk/lib/AST/Decl.cpp<br>
  cfe/trunk/lib/AST/DeclCXX.cpp<br>
  cfe/trunk/lib/AST/Expr.cpp<br>
  cfe/trunk/lib/AST/<wbr>ExprClassification.cpp<br>
  cfe/trunk/lib/Sema/Sema.cpp<br>
  cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
  cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp<br>
  cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp<br>
  cfe/trunk/lib/Sema/<wbr>SemaExprMember.cpp<br>
  cfe/trunk/lib/Sema/SemaInit.<wbr>cpp<br>
  cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
  cfe/trunk/lib/Sema/<wbr>SemaTemplateDeduction.cpp<br>
  cfe/trunk/lib/Sema/SemaType.<wbr>cpp<br>
  cfe/trunk/test/Parser/cxx1z-<wbr>decomposition.cpp<br>
  cfe/trunk/test/SemaCXX/cxx1z-<wbr>decomposition.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>CXXInheritance.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/CXXInheritance.h?<wbr>rev=278435&r1=278434&r2=<wbr>278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>CXXInheritance.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>CXXInheritance.h Thu Aug 11 17:25:46 2016<br>
@@ -172,7 +172,7 @@ public:<br>
  /// paths for a derived-to-base search.<br>
  explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true,<br>
             bool DetectVirtual = true)<br>
-Â Â Â : FindAmbiguities(<wbr>FindAmbiguities), RecordPaths(RecordPaths),<br>
+Â Â Â : Origin(), FindAmbiguities(<wbr>FindAmbiguities), RecordPaths(RecordPaths),<br>
     DetectVirtual(DetectVirtual), DetectedVirtual(nullptr),<br>
     NumDeclsFound(0) {}<br>
<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>Decl.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/Decl.h?rev=278435&<wbr>r1=278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>Decl.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>Decl.h Thu Aug 11 17:25:46 2016<br>
@@ -251,7 +251,7 @@ public:<br>
  // FIXME: Deprecated, move clients to getName().<br>
  std::string getNameAsString() const { return Name.getAsString(); }<br>
<br>
-Â void printName(raw_ostream &os) const { os << Name; }<br>
+Â virtual void printName(raw_ostream &os) const;<br>
<br>
  /// getDeclName - Get the actual, stored name of the declaration,<br>
  /// which may be a special name.<br>
@@ -1025,7 +1025,7 @@ public:<br>
  ///  void foo() { int x; static int y; extern int z; }<br>
  ///<br>
  bool isLocalVarDecl() const {<br>
-Â Â if (getKind() != Decl::Var)<br>
+Â Â if (getKind() != Decl::Var && getKind() != Decl::Decomposition)<br>
    return false;<br>
   if (const DeclContext *DC = getLexicalDeclContext())<br>
    return DC->getRedeclContext()-><wbr>isFunctionOrMethod();<br>
@@ -1040,7 +1040,7 @@ public:<br>
  /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but<br>
  /// excludes variables declared in blocks.<br>
  bool isFunctionOrMethodVarDecl() const {<br>
-Â Â if (getKind() != Decl::Var)<br>
+Â Â if (getKind() != Decl::Var && getKind() != Decl::Decomposition)<br>
    return false;<br>
   const DeclContext *DC = getLexicalDeclContext()-><wbr>getRedeclContext();<br>
   return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>DeclCXX.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/DeclCXX.h?rev=<wbr>278435&r1=278434&r2=278435&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>DeclCXX.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>DeclCXX.h Thu Aug 11 17:25:46 2016<br>
@@ -1147,6 +1147,12 @@ public:<br>
  /// \note This does NOT include a check for union-ness.<br>
  bool isEmpty() const { return data().Empty; }<br>
<br>
+Â /// \brief Determine whether this class has direct non-static data members.<br>
+Â bool hasDirectFields() const {<br>
+Â Â auto &D = data();<br>
+Â Â return D.HasPublicFields || D.HasProtectedFields || D.HasPrivateFields;<br>
+Â }<br>
+<br>
  /// Whether this class is polymorphic (C++ [class.virtual]),<br>
  /// which means that the class contains or inherits a virtual function.<br>
  bool isPolymorphic() const { return data().Polymorphic; }<br>
@@ -3451,6 +3457,8 @@ public:<br>
   return llvm::makeArrayRef(<wbr>getTrailingObjects<BindingDecl *>(), NumBindings);<br>
  }<br>
<br>
+Â void printName(raw_ostream &os) const override;<br>
+<br>
  static bool classof(const Decl *D) { return classofKind(D->getKind()); }<br>
  static bool classofKind(Kind K) { return K == Decomposition; }<br>
<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>UnresolvedSet.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/UnresolvedSet.h?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/UnresolvedSet.h?rev=<wbr>278435&r1=278434&r2=278435&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>UnresolvedSet.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>UnresolvedSet.h Thu Aug 11 17:25:46 2016<br>
@@ -38,7 +38,7 @@ class UnresolvedSetIterator : public llv<br>
    : iterator_adaptor_base(const_<wbr>cast<DeclAccessPair *>(Iter)) {}<br>
<br>
 public:<br>
-Â UnresolvedSetIterator() {}<br>
+Â UnresolvedSetIterator() = default;<br>
<br>
  NamedDecl *getDecl() const { return I->getDecl(); }<br>
  void setDecl(NamedDecl *ND) const { return I->setDecl(ND); }<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/<wbr>DiagnosticSemaKinds.td?rev=<wbr>278435&r1=278434&r2=278435&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td Thu Aug 11 17:25:46 2016<br>
@@ -385,6 +385,40 @@ def err_decomp_decl_template : Error<<br>
  "decomposition declaration template not supported">;<br>
 def err_decomp_decl_not_alone : Error<<br>
  "decomposition declaration must be the only declaration in its group">;<br>
+def err_decomp_decl_requires_init : Error<<br>
+Â "decomposition declaration %0 requires an initializer">;<br>
+def err_decomp_decl_paren_init : Error<<br>
+Â "decomposition declaration %0 cannot have a parenthesized initializer">;<br>
+def err_decomp_decl_wrong_number_<wbr>bindings : Error<<br>
+Â "type %0 decomposes into %2 elements, but %select{only |}3%1 "<br>
+Â "names were provided">;<br>
+def err_decomp_decl_unbindable_<wbr>type : Error<<br>
+Â "cannot decompose %select{union|non-class, non-array}1 type %2">;<br>
+def err_decomp_decl_multiple_<wbr>bases_with_members : Error<<br>
+Â "cannot decompose class type %1: "<br>
+Â "%select{its base classes %2 and|both it and its base class}0 %3 "<br>
+Â "have non-static data members">;<br>
+def err_decomp_decl_ambiguous_base : Error<<br>
+Â "cannot decompose members of ambiguous base class %1 of %0:%2">;<br>
+def err_decomp_decl_non_public_<wbr>base : Error<<br>
+Â "cannot decompose members of non-public base class %1 of %0">;<br>
+def err_decomp_decl_non_public_<wbr>member : Error<<br>
+Â "cannot decompose non-public member %0 of %1">;<br>
+def err_decomp_decl_anon_union_<wbr>member : Error<<br>
+Â "cannot decompose class type %1 because it has an anonymous "<br>
+Â "%select{struct|union} member">;<br>
+def err_decomp_decl_std_tuple_<wbr>element_not_specialized : Error<<br>
+Â "cannot decompose this type; 'std::tuple_element<%0>::type' "<br>
+Â "does not name a type">;<br>
+def err_decomp_decl_std_tuple_<wbr>size_not_constant : Error<<br>
+Â "cannot decompose this type; 'std::tuple_size<%0>::value' "<br>
+Â "is not a valid integral constant expression">;<br>
+def note_in_binding_decl_init : Note<<br>
+Â "in implicit initialization of binding declaration %0">;<br>
+<br>
+def err_std_type_trait_not_class_<wbr>template : Error<<br>
+Â "unsupported standard library implementation: "<br>
+Â "'std::%0' is not a class template">;<br>
<br>
 // C++ using declarations<br>
 def err_using_requires_qualname : Error<<br>
<br>
Modified: cfe/trunk/include/clang/Sema/<wbr>Initialization.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Sema/Initialization.h?<wbr>rev=278435&r1=278434&r2=<wbr>278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Sema/<wbr>Initialization.h (original)<br>
+++ cfe/trunk/include/clang/Sema/<wbr>Initialization.h Thu Aug 11 17:25:46 2016<br>
@@ -84,7 +84,10 @@ public:<br>
   EK_RelatedResult,<br>
   /// \brief The entity being initialized is a function parameter; function<br>
   /// is member of group of audited CF APIs.<br>
-Â Â EK_Parameter_CF_Audited<br>
+Â Â EK_Parameter_CF_Audited,<br>
+Â Â /// \brief The entity being initialized is a structured binding of a<br>
+Â Â /// decomposition declaration.<br>
+Â Â EK_Binding,<br>
<br>
   // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this<br>
   // enum as an index for its first %select. When modifying this list,<br>
@@ -126,9 +129,9 @@ private:<br>
  };<br>
<br>
  union {<br>
-Â Â /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or<br>
-Â Â /// FieldDecl, respectively.<br>
-Â Â DeclaratorDecl *VariableOrMember;<br>
+Â Â /// \brief When Kind == EK_Variable, EK_Member or EK_Binding, the VarDecl,<br>
+Â Â /// FieldDecl or BindingDecl, respectively.<br>
+Â Â ValueDecl *VariableOrMember;<br>
<br>
   /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where<br>
   /// result type was implicitly changed to accommodate ARC semantics.<br>
@@ -180,6 +183,12 @@ private:<br>
   : Kind(EK_Member), Parent(Parent), Type(Member->getType()),<br>
    ManglingNumber(0), VariableOrMember(Member) { }<br>
<br>
+Â /// \brief Create the initialization entity for a binding.<br>
+Â InitializedEntity(BindingDecl *Binding, QualType Type,<br>
+Â Â Â Â Â Â Â Â Â Â const InitializedEntity &Parent)<br>
+Â Â : Kind(EK_Binding), Parent(&Parent), Type(Type),<br>
+Â Â Â ManglingNumber(0), VariableOrMember(Binding) {}<br>
+<br>
  /// \brief Create the initialization entity for an array element.<br>
  InitializedEntity(ASTContext &Context, unsigned Index,<br>
           const InitializedEntity &Parent);<br>
@@ -314,6 +323,13 @@ public:<br>
   return InitializedEntity(Context, Index, Parent);<br>
  }<br>
<br>
+Â /// \brief Create the initialization entity for a structured binding.<br>
+Â static InitializedEntity InitializeBinding(const InitializedEntity &Parent,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â BindingDecl *Binding,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â QualType Type) {<br>
+Â Â return InitializedEntity(Binding, Type, Parent);<br>
+Â }<br>
+<br>
  /// \brief Create the initialization entity for a lambda capture.<br>
  static InitializedEntity InitializeLambdaCapture(<wbr>IdentifierInfo *VarID,<br>
                          QualType FieldType,<br>
@@ -355,7 +371,7 @@ public:<br>
<br>
  /// \brief Retrieve the variable, parameter, or field being<br>
  /// initialized.<br>
-Â DeclaratorDecl *getDecl() const;<br>
+Â ValueDecl *getDecl() const;<br>
<br>
  /// \brief Retrieve the ObjectiveC method being initialized.<br>
  ObjCMethodDecl *getMethodDecl() const { return MethodDecl; }<br>
<br>
Modified: cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Sema/Sema.h?rev=278435&<wbr>r1=278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Sema/<wbr>Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/<wbr>Sema.h Thu Aug 11 17:25:46 2016<br>
@@ -1728,7 +1728,9 @@ public:<br>
  // Returns true if the variable declaration is a redeclaration<br>
  bool CheckVariableDeclaration(<wbr>VarDecl *NewVD, LookupResult &Previous);<br>
  void CheckVariableDeclarationType(<wbr>VarDecl *NewVD);<br>
-Â void CheckCompleteVariableDeclarati<wbr>on(VarDecl *var);<br>
+Â void CheckCompleteVariableDeclarati<wbr>on(VarDecl *VD, InitializedEntity &Entity);<br>
+Â void CheckCompleteDecompositionDecl<wbr>aration(DecompositionDecl *DD,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â InitializedEntity &Entity);<br>
  void MaybeSuggestAddingStaticToDecl<wbr>(const FunctionDecl *D);<br>
<br>
  NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,<br>
@@ -3970,6 +3972,12 @@ public:<br>
              bool SuppressQualifierCheck = false,<br>
              ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);<br>
<br>
+Â ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation OpLoc,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const CXXScopeSpec &SS, FieldDecl *Field,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â DeclAccessPair FoundDecl,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const DeclarationNameInfo &MemberNameInfo);<br>
+<br>
  ExprResult PerformMemberExprBaseConversio<wbr>n(Expr *Base, bool IsArrow);<br>
<br>
  bool CheckQualifiedMemberReference(<wbr>Expr *BaseExpr, QualType BaseType,<br>
@@ -5772,6 +5780,10 @@ public:<br>
               TemplateParameterList **OuterTemplateParamLists,<br>
                 SkipBodyInfo *SkipBody = nullptr);<br>
<br>
+Â TemplateArgumentLoc getTrivialTemplateArgumentLoc(<wbr>const TemplateArgument &Arg,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â QualType NTTPType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation Loc);<br>
+<br>
  void translateTemplateArguments(<wbr>const ASTTemplateArgsPtr &In,<br>
                  TemplateArgumentListInfo &Out);<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/ASTDumper.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>ASTDumper.cpp?rev=278435&r1=<wbr>278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/ASTDumper.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTDumper.<wbr>cpp Thu Aug 11 17:25:46 2016<br>
@@ -429,6 +429,7 @@ namespace {<br>
   void VisitFieldDecl(const FieldDecl *D);<br>
   void VisitVarDecl(const VarDecl *D);<br>
   void VisitDecompositionDecl(const DecompositionDecl *D);<br>
+Â Â void VisitBindingDecl(const BindingDecl *D);<br>
   void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);<br>
   void VisitImportDecl(const ImportDecl *D);<br>
   void VisitPragmaCommentDecl(const PragmaCommentDecl *D);<br>
@@ -1224,6 +1225,13 @@ void ASTDumper::<wbr>VisitDecompositionDecl(c<br>
   dumpDecl(B);<br>
 }<br>
<br>
+void ASTDumper::VisitBindingDecl(<wbr>const BindingDecl *D) {<br>
+Â dumpName(D);<br>
+Â dumpType(D->getType());<br>
+Â if (auto *E = D->getBinding())<br>
+Â Â dumpStmt(E);<br>
+}<br>
+<br>
 void ASTDumper::<wbr>VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {<br>
  dumpStmt(D->getAsmString());<br>
 }<br>
<br>
Modified: cfe/trunk/lib/AST/Decl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>Decl.cpp?rev=278435&r1=278434&<wbr>r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/Decl.cpp (original)<br>
+++ cfe/trunk/lib/AST/Decl.cpp Thu Aug 11 17:25:46 2016<br>
@@ -1395,6 +1395,10 @@ static LinkageInfo getLVForDecl(const Na<br>
  return clang::LinkageComputer::<wbr>getLVForDecl(D, computation);<br>
 }<br>
<br>
+void NamedDecl::printName(raw_<wbr>ostream &os) const {<br>
+Â os << Name;<br>
+}<br>
+<br>
 std::string NamedDecl::<wbr>getQualifiedNameAsString() const {<br>
  std::string QualName;<br>
  llvm::raw_string_ostream OS(QualName);<br>
@@ -1481,7 +1485,7 @@ void NamedDecl::printQualifiedName(<wbr>raw_o<br>
   OS << "::";<br>
  }<br>
<br>
-Â if (getDeclName())<br>
+Â if (getDeclName() || isa<DecompositionDecl>(this))<br>
   OS << *this;<br>
  else<br>
   OS << "(anonymous)";<br>
<br>
Modified: cfe/trunk/lib/AST/DeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>DeclCXX.cpp?rev=278435&r1=<wbr>278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Aug 11 17:25:46 2016<br>
@@ -2344,6 +2344,18 @@ DecompositionDecl *DecompositionDecl::Cr<br>
  return Result;<br>
 }<br>
<br>
+void DecompositionDecl::printName(<wbr>llvm::raw_ostream &os) const {<br>
+Â os << '[';<br>
+Â bool Comma = false;<br>
+Â for (auto *B : bindings()) {<br>
+Â Â if (Comma)<br>
+Â Â Â os << ", ";<br>
+Â Â B->printName(os);<br>
+Â Â Comma = true;<br>
+Â }<br>
+Â os << ']';<br>
+}<br>
+<br>
 MSPropertyDecl *MSPropertyDecl::Create(<wbr>ASTContext &C, DeclContext *DC,<br>
                    SourceLocation L, DeclarationName N,<br>
                    QualType T, TypeSourceInfo *TInfo,<br>
<br>
Modified: cfe/trunk/lib/AST/Expr.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>Expr.cpp?rev=278435&r1=278434&<wbr>r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/Expr.cpp (original)<br>
+++ cfe/trunk/lib/AST/Expr.cpp Thu Aug 11 17:25:46 2016<br>
@@ -3308,11 +3308,16 @@ FieldDecl *Expr::getSourceBitField() {<br>
    if (Ivar->isBitField())<br>
     return Ivar;<br>
<br>
-Â if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E))<br>
+Â if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) {<br>
   if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef-><wbr>getDecl()))<br>
    if (Field->isBitField())<br>
     return Field;<br>
<br>
+Â Â if (BindingDecl *BD = dyn_cast<BindingDecl>(DeclRef-<wbr>>getDecl()))<br>
+Â Â Â if (Expr *E = BD->getBinding())<br>
+Â Â Â Â return E->getSourceBitField();<br>
+Â }<br>
+<br>
  if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) {<br>
   if (BinOp->isAssignmentOp() && BinOp->getLHS())<br>
    return BinOp->getLHS()-><wbr>getSourceBitField();<br>
@@ -3329,6 +3334,7 @@ FieldDecl *Expr::getSourceBitField() {<br>
 }<br>
<br>
 bool Expr::refersToVectorElement() const {<br>
+Â // FIXME: Why do we not just look at the ObjectKind here?<br>
  const Expr *E = this->IgnoreParens();<br>
<br>
  while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {<br>
@@ -3345,6 +3351,11 @@ bool Expr::refersToVectorElement() const<br>
  if (isa<ExtVectorElementExpr>(E))<br>
   return true;<br>
<br>
+Â if (auto *DRE = dyn_cast<DeclRefExpr>(E))<br>
+Â Â if (auto *BD = dyn_cast<BindingDecl>(DRE-><wbr>getDecl()))<br>
+Â Â Â if (auto *E = BD->getBinding())<br>
+Â Â Â Â return E->refersToVectorElement();<br>
+<br>
  return false;<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/<wbr>ExprClassification.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>ExprClassification.cpp?rev=<wbr>278435&r1=278434&r2=278435&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/<wbr>ExprClassification.cpp (original)<br>
+++ cfe/trunk/lib/AST/<wbr>ExprClassification.cpp Thu Aug 11 17:25:46 2016<br>
@@ -429,6 +429,7 @@ static Cl::Kinds ClassifyDecl(ASTContext<br>
  else<br>
   islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||<br>
        isa<IndirectFieldDecl>(D) ||<br>
+Â Â Â Â Â Â Â Â isa<BindingDecl>(D) ||<br>
        (Ctx.getLangOpts().CPlusPlus &&<br>
         (isa<FunctionDecl>(D) || isa<MSPropertyDecl>(D) ||<br>
         isa<FunctionTemplateDecl>(D)))<wbr>;<br>
<br>
Modified: cfe/trunk/lib/Sema/Sema.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>Sema.cpp?rev=278435&r1=278434&<wbr>r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/Sema.cpp (original)<br>
+++ cfe/trunk/lib/Sema/Sema.cpp Thu Aug 11 17:25:46 2016<br>
@@ -28,6 +28,7 @@<br>
 #include "clang/Sema/CXXFieldCollector.<wbr>h"<br>
 #include "clang/Sema/DelayedDiagnostic.<wbr>h"<br>
 #include "clang/Sema/<wbr>ExternalSemaSource.h"<br>
+#include "clang/Sema/Initialization.h"<br>
 #include "clang/Sema/<wbr>MultiplexExternalSemaSource.h"<br>
 #include "clang/Sema/ObjCMethodList.h"<br>
 #include "clang/Sema/<wbr>PrettyDeclStackTrace.h"<br>
@@ -809,7 +810,9 @@ void Sema::<wbr>ActOnEndOfTranslationUnit() {<br>
                  diag::err_tentative_def_<wbr>incomplete_type))<br>
    VD->setInvalidDecl();<br>
<br>
-Â Â CheckCompleteVariableDeclarati<wbr>on(VD);<br>
+Â Â // No initialization is performed for a tentative definition.<br>
+Â Â InitializedEntity Entity = InitializedEntity::<wbr>InitializeVariable(VD);<br>
+Â Â CheckCompleteVariableDeclarati<wbr>on(VD, Entity);<br>
<br>
   // Notify the consumer that we've completed a tentative definition.<br>
   if (!VD->isInvalidDecl())<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaDecl.cpp?rev=278435&r1=<wbr>278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp Thu Aug 11 17:25:46 2016<br>
@@ -43,7 +43,6 @@<br>
 #include "clang/Sema/SemaInternal.h"<br>
 #include "clang/Sema/Template.h"<br>
 #include "llvm/ADT/SmallString.h"<br>
-#include "llvm/ADT/StringExtras.h"<br>
 #include "llvm/ADT/Triple.h"<br>
 #include <algorithm><br>
 #include <cstring><br>
@@ -6534,157 +6533,6 @@ NamedDecl *Sema::ActOnVariableDeclarator<br>
  return NewVD;<br>
 }<br>
<br>
-NamedDecl *<br>
-Sema::<wbr>ActOnDecompositionDeclarator(<wbr>Scope *S, Declarator &D,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â MultiTemplateParamsArg TemplateParamLists) {<br>
-Â assert(D.<wbr>isDecompositionDeclarator());<br>
-Â const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator()<wbr>;<br>
-<br>
-Â // The syntax only allows a decomposition declarator as a simple-declaration<br>
-Â // or a for-range-declaration, but we parse it in more cases than that.<br>
-Â if (!D.<wbr>mayHaveDecompositionDeclarator<wbr>()) {<br>
-Â Â Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)<br>
-Â Â Â << Decomp.getSourceRange();<br>
-Â Â return nullptr;<br>
-Â }<br>
-<br>
-Â if (!TemplateParamLists.empty()) {<br>
-Â Â // FIXME: There's no rule against this, but there are also no rules that<br>
-Â Â // would actually make it usable, so we reject it for now.<br>
-Â Â Diag(TemplateParamLists.front(<wbr>)->getTemplateLoc(),<br>
-Â Â Â Â Â diag::err_decomp_decl_<wbr>template);<br>
-Â Â return nullptr;<br>
-Â }<br>
-<br>
-Â Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ? diag::warn_cxx14_compat_<wbr>decomp_decl<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â : diag::ext_decomp_decl)<br>
-Â Â Â << Decomp.getSourceRange();<br>
-<br>
-Â // The semantic context is always just the current context.<br>
-Â DeclContext *const DC = CurContext;<br>
-<br>
-Â // C++1z [dcl.dcl]/8:<br>
-Â //Â Â The decl-specifier-seq shall contain only the type-specifier auto<br>
-Â //Â Â and cv-qualifiers.<br>
-Â auto &DS = D.getDeclSpec();<br>
-Â {<br>
-Â Â SmallVector<StringRef, 8> BadSpecifiers;<br>
-Â Â SmallVector<SourceLocation, 8> BadSpecifierLocs;<br>
-Â Â if (auto SCS = DS.getStorageClassSpec()) {<br>
-Â Â Â BadSpecifiers.push_back(<wbr>DeclSpec::getSpecifierName(<wbr>SCS));<br>
-Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getStorageClassSpecLoc());<br>
-Â Â }<br>
-Â Â if (auto TSCS = DS.getThreadStorageClassSpec()<wbr>) {<br>
-Â Â Â BadSpecifiers.push_back(<wbr>DeclSpec::getSpecifierName(<wbr>TSCS));<br>
-Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getThreadStorageClassSpecLoc()<wbr>);<br>
-Â Â }<br>
-Â Â if (DS.isConstexprSpecified()) {<br>
-Â Â Â BadSpecifiers.push_back("<wbr>constexpr");<br>
-Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getConstexprSpecLoc());<br>
-Â Â }<br>
-Â Â if (DS.isInlineSpecified()) {<br>
-Â Â Â BadSpecifiers.push_back("<wbr>inline");<br>
-Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getInlineSpecLoc());<br>
-Â Â }<br>
-Â Â if (!BadSpecifiers.empty()) {<br>
-Â Â Â auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);<br>
-Â Â Â Err << (int)BadSpecifiers.size()<br>
-Â Â Â Â Â << llvm::join(BadSpecifiers.<wbr>begin(), BadSpecifiers.end(), " ");<br>
-Â Â Â // Don't add FixItHints to remove the specifiers; we do still respect<br>
-Â Â Â // them when building the underlying variable.<br>
-Â Â Â for (auto Loc : BadSpecifierLocs)<br>
-Â Â Â Â Err << SourceRange(Loc, Loc);<br>
-Â Â }<br>
-Â Â // We can't recover from it being declared as a typedef.<br>
-Â Â if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)<br>
-Â Â Â return nullptr;<br>
-Â }<br>
-<br>
-Â TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);<br>
-Â QualType R = TInfo->getType();<br>
-<br>
-Â if (<wbr>DiagnoseUnexpandedParameterPac<wbr>k(D.getIdentifierLoc(), TInfo,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â UPPC_DeclarationType))<br>
-Â Â D.setInvalidType();<br>
-<br>
-Â // The syntax only allows a single ref-qualifier prior to the decomposition<br>
-Â // declarator. No other declarator chunks are permitted. Also check the type<br>
-Â // specifier here.<br>
-Â if (DS.getTypeSpecType() != DeclSpec::TST_auto ||<br>
-Â Â Â D.hasGroupingParens() || D.getNumTypeObjects() > 1 ||<br>
-Â Â Â (D.getNumTypeObjects() == 1 &&<br>
-Â Â Â Â D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) {<br>
-Â Â Diag(Decomp.getLSquareLoc(),<br>
-Â Â Â Â Â (D.hasGroupingParens() ||<br>
-Â Â Â Â Â (D.getNumTypeObjects() &&<br>
-Â Â Â Â Â Â D.getTypeObject(0).Kind == DeclaratorChunk::Paren))<br>
-Â Â Â Â Â Â Â ? diag::err_decomp_decl_parens<br>
-Â Â Â Â Â Â Â : diag::err_decomp_decl_type)<br>
-Â Â Â Â << R;<br>
-<br>
-Â Â // In most cases, there's no actual problem with an explicitly-specified<br>
-Â Â // type, but a function type won't work here, and ActOnVariableDeclarator<br>
-Â Â // shouldn't be called for such a type.<br>
-Â Â if (R->isFunctionType())<br>
-Â Â Â D.setInvalidType();<br>
-Â }<br>
-<br>
-Â // Build the BindingDecls.<br>
-Â SmallVector<BindingDecl*, 8> Bindings;<br>
-<br>
-Â // Build the BindingDecls.<br>
-Â for (auto &B : D.getDecompositionDeclarator()<wbr>.bindings()) {<br>
-Â Â // Check for name conflicts.<br>
-Â Â DeclarationNameInfo NameInfo(B.Name, B.NameLoc);<br>
-Â Â LookupResult Previous(*this, NameInfo, LookupOrdinaryName,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â ForRedeclaration);<br>
-Â Â LookupName(Previous, S,<br>
-Â Â Â Â Â Â Â Â /*CreateBuiltins*/DC-><wbr>getRedeclContext()-><wbr>isTranslationUnit());<br>
-<br>
-Â Â // It's not permitted to shadow a template parameter name.<br>
-Â Â if (Previous.isSingleResult() &&<br>
-Â Â Â Â Previous.getFoundDecl()-><wbr>isTemplateParameter()) {<br>
-Â Â Â DiagnoseTemplateParameterShado<wbr>w(D.getIdentifierLoc(),<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Previous.getFoundDecl());<br>
-Â Â Â Previous.clear();<br>
-Â Â }<br>
-<br>
-Â Â bool ConsiderLinkage = DC->isFunctionOrMethod() &&<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â DS.getStorageClassSpec() == DeclSpec::SCS_extern;<br>
-Â Â FilterLookupForScope(Previous, DC, S, ConsiderLinkage,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â /*AllowInlineNamespace*/false)<wbr>;<br>
-Â Â if (!Previous.empty()) {<br>
-Â Â Â auto *Old = Previous.<wbr>getRepresentativeDecl();<br>
-Â Â Â Diag(B.NameLoc, diag::err_redefinition) << B.Name;<br>
-Â Â Â Diag(Old->getLocation(), diag::note_previous_<wbr>definition);<br>
-Â Â }<br>
-<br>
-Â Â auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);<br>
-Â Â PushOnScopeChains(BD, S, true);<br>
-Â Â Bindings.push_back(BD);<br>
-Â Â ParsingInitForAutoVars.insert(<wbr>BD);<br>
-Â }<br>
-<br>
-Â // There are no prior lookup results for the variable itself, because it<br>
-Â // is unnamed.<br>
-Â DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Decomp.getLSquareLoc());<br>
-Â LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);<br>
-<br>
-Â // Build the variable that holds the non-decomposed object.<br>
-Â bool AddToScope = true;<br>
-Â NamedDecl *New =<br>
-Â Â Â ActOnVariableDeclarator(S, D, DC, TInfo, Previous,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â MultiTemplateParamsArg(), AddToScope, Bindings);<br>
-Â CurContext->addHiddenDecl(New)<wbr>;<br>
-<br>
-Â if (<wbr>isInOpenMPDeclareTargetContext<wbr>())<br>
-Â Â checkDeclIsAllowedInOpenMPTarg<wbr>et(nullptr, New);<br>
-<br>
-Â return New;<br>
-}<br>
-<br>
 /// Enum describing the %select options in diag::warn_decl_shadow.<br>
 enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field };<br>
<br>
@@ -9604,6 +9452,9 @@ QualType Sema::<wbr>deduceVarTypeFromInitiali<br>
  assert((!VDecl || !VDecl->isInitCapture()) &&<br>
     "init captures are expected to be deduced prior to initialization");<br>
<br>
+Â // FIXME: Deduction for a decomposition declaration does weird things if the<br>
+Â // initializer is an array.<br>
+<br>
  ArrayRef<Expr *> DeduceInits = Init;<br>
  if (DirectInit) {<br>
   if (auto *PL = dyn_cast<ParenListExpr>(Init))<br>
@@ -9713,6 +9564,11 @@ void Sema::AddInitializerToDecl(<wbr>Decl *Re<br>
   return;<br>
  }<br>
<br>
+Â // C++1z [dcl.dcl]p1 grammar implies that a parenthesized initializer is not<br>
+Â // permitted.<br>
+Â if (isa<DecompositionDecl>(VDecl) && DirectInit && isa<ParenListExpr>(Init))<br>
+Â Â Diag(VDecl->getLocation(), diag::err_decomp_decl_paren_<wbr>init) << VDecl;<br>
+<br>
  // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.<br>
  if (TypeMayContainAuto && VDecl->getType()-><wbr>isUndeducedType()) {<br>
   // Attempt typo correction early so that the type of the init expression can<br>
@@ -9864,8 +9720,8 @@ void Sema::AddInitializerToDecl(<wbr>Decl *Re<br>
<br>
  // Perform the initialization.<br>
  ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);<br>
+Â InitializedEntity Entity = InitializedEntity::<wbr>InitializeVariable(VDecl);<br>
  if (!VDecl->isInvalidDecl()) {<br>
-Â Â InitializedEntity Entity = InitializedEntity::<wbr>InitializeVariable(VDecl);<br>
   InitializationKind Kind =<br>
     DirectInit<br>
       ? CXXDirectInit<br>
@@ -10116,7 +9972,7 @@ void Sema::AddInitializerToDecl(<wbr>Decl *Re<br>
   VDecl->setInitStyle(VarDecl::<wbr>ListInit);<br>
  }<br>
<br>
-Â CheckCompleteVariableDeclarati<wbr>on(VDecl);<br>
+Â CheckCompleteVariableDeclarati<wbr>on(VDecl, Entity);<br>
 }<br>
<br>
 /// ActOnInitializerError - Given that there was an error parsing an<br>
@@ -10173,6 +10029,13 @@ void Sema::ActOnUninitializedDecl(<wbr>Decl *<br>
  if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {<br>
   QualType Type = Var->getType();<br>
<br>
+Â Â // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory.<br>
+Â Â if (isa<DecompositionDecl>(<wbr>RealDecl)) {<br>
+Â Â Â Diag(Var->getLocation(), diag::err_decomp_decl_<wbr>requires_init) << Var;<br>
+Â Â Â Var->setInvalidDecl();<br>
+Â Â Â return;<br>
+Â Â }<br>
+<br>
   // C++11 [dcl.spec.auto]p3<br>
   if (TypeMayContainAuto && Type->getContainedAutoType()) {<br>
    Diag(Var->getLocation(), diag::err_auto_var_requires_<wbr>init)<br>
@@ -10394,7 +10257,7 @@ void Sema::ActOnUninitializedDecl(<wbr>Decl *<br>
    Var->setInitStyle(VarDecl::<wbr>CallInit);<br>
   }<br>
<br>
-Â Â CheckCompleteVariableDeclarati<wbr>on(Var);<br>
+Â Â CheckCompleteVariableDeclarati<wbr>on(Var, Entity);<br>
  }<br>
 }<br>
<br>
@@ -10471,7 +10334,8 @@ Sema::<wbr>ActOnCXXForRangeIdentifier(<wbr>Scope *<br>
            AttrEnd.isValid() ? AttrEnd : IdentLoc);<br>
 }<br>
<br>
-void Sema::<wbr>CheckCompleteVariableDeclarati<wbr>on(VarDecl *var) {<br>
+void Sema::<wbr>CheckCompleteVariableDeclarati<wbr>on(VarDecl *var,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â InitializedEntity &Entity) {<br>
  if (var->isInvalidDecl()) return;<br>
<br>
  if (getLangOpts().OpenCL) {<br>
@@ -10580,6 +10444,9 @@ void Sema::<wbr>CheckCompleteVariableDeclarat<br>
  // All the following checks are C++ only.<br>
  if (!getLangOpts().CPlusPlus) return;<br>
<br>
+Â if (auto *DD = dyn_cast<DecompositionDecl>(<wbr>var))<br>
+Â Â CheckCompleteDecompositionDecl<wbr>aration(DD, Entity);<br>
+<br>
  QualType type = var->getType();<br>
  if (type->isDependentType()) return;<br>
<br>
@@ -10680,9 +10547,13 @@ Sema::FinalizeDeclaration(Decl *ThisDecl<br>
  if (!VD)<br>
   return;<br>
<br>
-Â if (auto *DD = dyn_cast<DecompositionDecl>(<wbr>ThisDecl))<br>
-Â Â for (auto *BD : DD->bindings())<br>
+Â if (auto *DD = dyn_cast<DecompositionDecl>(<wbr>ThisDecl)) {<br>
+Â Â for (auto *BD : DD->bindings()) {<br>
+Â Â Â if (ThisDecl->isInvalidDecl())<br>
+Â Â Â Â BD->setInvalidDecl();<br>
    FinalizeDeclaration(BD);<br>
+Â Â }<br>
+Â }<br>
<br>
  checkAttributesAfterMerging(*<wbr>this, *VD);<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp?rev=278435&r1=<wbr>278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp Thu Aug 11 17:25:46 2016<br>
@@ -39,6 +39,7 @@<br>
 #include "clang/Sema/Template.h"<br>
 #include "llvm/ADT/STLExtras.h"<br>
 #include "llvm/ADT/SmallString.h"<br>
+#include "llvm/ADT/StringExtras.h"<br>
 #include <map><br>
 #include <set><br>
<br>
@@ -664,6 +665,753 @@ bool Sema::MergeCXXFunctionDecl(<wbr>Function<br>
  return Invalid;<br>
 }<br>
<br>
+NamedDecl *<br>
+Sema::<wbr>ActOnDecompositionDeclarator(<wbr>Scope *S, Declarator &D,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â MultiTemplateParamsArg TemplateParamLists) {<br>
+Â assert(D.<wbr>isDecompositionDeclarator());<br>
+Â const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator()<wbr>;<br>
+<br>
+Â // The syntax only allows a decomposition declarator as a simple-declaration<br>
+Â // or a for-range-declaration, but we parse it in more cases than that.<br>
+Â if (!D.<wbr>mayHaveDecompositionDeclarator<wbr>()) {<br>
+Â Â Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)<br>
+Â Â Â << Decomp.getSourceRange();<br>
+Â Â return nullptr;<br>
+Â }<br>
+<br>
+Â if (!TemplateParamLists.empty()) {<br>
+Â Â // FIXME: There's no rule against this, but there are also no rules that<br>
+Â Â // would actually make it usable, so we reject it for now.<br>
+Â Â Diag(TemplateParamLists.front(<wbr>)->getTemplateLoc(),<br>
+Â Â Â Â Â diag::err_decomp_decl_<wbr>template);<br>
+Â Â return nullptr;<br>
+Â }<br>
+<br>
+Â Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ? diag::warn_cxx14_compat_<wbr>decomp_decl<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â : diag::ext_decomp_decl)<br>
+Â Â Â << Decomp.getSourceRange();<br>
+<br>
+Â // The semantic context is always just the current context.<br>
+Â DeclContext *const DC = CurContext;<br>
+<br>
+Â // C++1z [dcl.dcl]/8:<br>
+Â //Â Â The decl-specifier-seq shall contain only the type-specifier auto<br>
+Â //Â Â and cv-qualifiers.<br>
+Â auto &DS = D.getDeclSpec();<br>
+Â {<br>
+Â Â SmallVector<StringRef, 8> BadSpecifiers;<br>
+Â Â SmallVector<SourceLocation, 8> BadSpecifierLocs;<br>
+Â Â if (auto SCS = DS.getStorageClassSpec()) {<br>
+Â Â Â BadSpecifiers.push_back(<wbr>DeclSpec::getSpecifierName(<wbr>SCS));<br>
+Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getStorageClassSpecLoc());<br>
+Â Â }<br>
+Â Â if (auto TSCS = DS.getThreadStorageClassSpec()<wbr>) {<br>
+Â Â Â BadSpecifiers.push_back(<wbr>DeclSpec::getSpecifierName(<wbr>TSCS));<br>
+Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getThreadStorageClassSpecLoc()<wbr>);<br>
+Â Â }<br>
+Â Â if (DS.isConstexprSpecified()) {<br>
+Â Â Â BadSpecifiers.push_back("<wbr>constexpr");<br>
+Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getConstexprSpecLoc());<br>
+Â Â }<br>
+Â Â if (DS.isInlineSpecified()) {<br>
+Â Â Â BadSpecifiers.push_back("<wbr>inline");<br>
+Â Â Â BadSpecifierLocs.push_back(DS.<wbr>getInlineSpecLoc());<br>
+Â Â }<br>
+Â Â if (!BadSpecifiers.empty()) {<br>
+Â Â Â auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);<br>
+Â Â Â Err << (int)BadSpecifiers.size()<br>
+Â Â Â Â Â << llvm::join(BadSpecifiers.<wbr>begin(), BadSpecifiers.end(), " ");<br>
+Â Â Â // Don't add FixItHints to remove the specifiers; we do still respect<br>
+Â Â Â // them when building the underlying variable.<br>
+Â Â Â for (auto Loc : BadSpecifierLocs)<br>
+Â Â Â Â Err << SourceRange(Loc, Loc);<br>
+Â Â }<br>
+Â Â // We can't recover from it being declared as a typedef.<br>
+Â Â if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)<br>
+Â Â Â return nullptr;<br>
+Â }<br>
+<br>
+Â TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);<br>
+Â QualType R = TInfo->getType();<br>
+<br>
+Â if (<wbr>DiagnoseUnexpandedParameterPac<wbr>k(D.getIdentifierLoc(), TInfo,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â UPPC_DeclarationType))<br>
+Â Â D.setInvalidType();<br>
+<br>
+Â // The syntax only allows a single ref-qualifier prior to the decomposition<br>
+Â // declarator. No other declarator chunks are permitted. Also check the type<br>
+Â // specifier here.<br>
+Â if (DS.getTypeSpecType() != DeclSpec::TST_auto ||<br>
+Â Â Â D.hasGroupingParens() || D.getNumTypeObjects() > 1 ||<br>
+Â Â Â (D.getNumTypeObjects() == 1 &&<br>
+Â Â Â Â D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) {<br>
+Â Â Diag(Decomp.getLSquareLoc(),<br>
+Â Â Â Â Â (D.hasGroupingParens() ||<br>
+Â Â Â Â Â (D.getNumTypeObjects() &&<br>
+Â Â Â Â Â Â D.getTypeObject(0).Kind == DeclaratorChunk::Paren))<br>
+Â Â Â Â Â Â Â ? diag::err_decomp_decl_parens<br>
+Â Â Â Â Â Â Â : diag::err_decomp_decl_type)<br>
+Â Â Â Â << R;<br>
+<br>
+Â Â // In most cases, there's no actual problem with an explicitly-specified<br>
+Â Â // type, but a function type won't work here, and ActOnVariableDeclarator<br>
+Â Â // shouldn't be called for such a type.<br>
+Â Â if (R->isFunctionType())<br>
+Â Â Â D.setInvalidType();<br>
+Â }<br>
+<br>
+Â // Build the BindingDecls.<br>
+Â SmallVector<BindingDecl*, 8> Bindings;<br>
+<br>
+Â // Build the BindingDecls.<br>
+Â for (auto &B : D.getDecompositionDeclarator()<wbr>.bindings()) {<br>
+Â Â // Check for name conflicts.<br>
+Â Â DeclarationNameInfo NameInfo(B.Name, B.NameLoc);<br>
+Â Â LookupResult Previous(*this, NameInfo, LookupOrdinaryName,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â ForRedeclaration);<br>
+Â Â LookupName(Previous, S,<br>
+Â Â Â Â Â Â Â Â /*CreateBuiltins*/DC-><wbr>getRedeclContext()-><wbr>isTranslationUnit());<br>
+<br>
+Â Â // It's not permitted to shadow a template parameter name.<br>
+Â Â if (Previous.isSingleResult() &&<br>
+Â Â Â Â Previous.getFoundDecl()-><wbr>isTemplateParameter()) {<br>
+Â Â Â DiagnoseTemplateParameterShado<wbr>w(D.getIdentifierLoc(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Previous.getFoundDecl());<br>
+Â Â Â Previous.clear();<br>
+Â Â }<br>
+<br>
+Â Â bool ConsiderLinkage = DC->isFunctionOrMethod() &&<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â DS.getStorageClassSpec() == DeclSpec::SCS_extern;<br>
+Â Â FilterLookupForScope(Previous, DC, S, ConsiderLinkage,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â /*AllowInlineNamespace*/false)<wbr>;<br>
+Â Â if (!Previous.empty()) {<br>
+Â Â Â auto *Old = Previous.<wbr>getRepresentativeDecl();<br>
+Â Â Â Diag(B.NameLoc, diag::err_redefinition) << B.Name;<br>
+Â Â Â Diag(Old->getLocation(), diag::note_previous_<wbr>definition);<br>
+Â Â }<br>
+<br>
+Â Â auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);<br>
+Â Â PushOnScopeChains(BD, S, true);<br>
+Â Â Bindings.push_back(BD);<br>
+Â Â ParsingInitForAutoVars.insert(<wbr>BD);<br>
+Â }<br>
+<br>
+Â // There are no prior lookup results for the variable itself, because it<br>
+Â // is unnamed.<br>
+Â DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Decomp.getLSquareLoc());<br>
+Â LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);<br>
+<br>
+Â // Build the variable that holds the non-decomposed object.<br>
+Â bool AddToScope = true;<br>
+Â NamedDecl *New =<br>
+Â Â Â ActOnVariableDeclarator(S, D, DC, TInfo, Previous,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â MultiTemplateParamsArg(), AddToScope, Bindings);<br>
+Â CurContext->addHiddenDecl(New)<wbr>;<br>
+<br>
+Â if (<wbr>isInOpenMPDeclareTargetContext<wbr>())<br>
+Â Â checkDeclIsAllowedInOpenMPTarg<wbr>et(nullptr, New);<br>
+<br>
+Â return New;<br>
+}<br>
+<br>
+static bool checkSimpleDecomposition(<br>
+Â Â Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src,<br>
+Â Â QualType DecompType, llvm::APSInt NumElems, QualType ElemType,<br>
+Â Â llvm::function_ref<ExprResult(<wbr>SourceLocation, Expr *, unsigned)> GetInit) {<br>
+Â if ((int64_t)Bindings.size() != NumElems) {<br>
+Â Â S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_<wbr>number_bindings)<br>
+Â Â Â Â << DecompType << (unsigned)Bindings.size() << NumElems.toString(10)<br>
+Â Â Â Â << (NumElems < Bindings.size());<br>
+Â Â return true;<br>
+Â }<br>
+<br>
+Â unsigned I = 0;<br>
+Â for (auto *B : Bindings) {<br>
+Â Â SourceLocation Loc = B->getLocation();<br>
+Â Â ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+Â Â E = GetInit(Loc, E.get(), I++);<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+Â Â B->setBinding(ElemType, E.get());<br>
+Â }<br>
+<br>
+Â return false;<br>
+}<br>
+<br>
+static bool checkArrayLikeDecomposition(<wbr>Sema &S,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ArrayRef<BindingDecl *> Bindings,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ValueDecl *Src, QualType DecompType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â llvm::APSInt NumElems,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â QualType ElemType) {<br>
+Â return checkSimpleDecomposition(<br>
+Â Â Â S, Bindings, Src, DecompType, NumElems, ElemType,<br>
+Â Â Â [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult {<br>
+Â Â Â Â ExprResult E = S.ActOnIntegerConstant(Loc, I);<br>
+Â Â Â Â if (E.isInvalid())<br>
+Â Â Â Â Â return ExprError();<br>
+Â Â Â Â return S.<wbr>CreateBuiltinArraySubscriptExp<wbr>r(Base, Loc, E.get(), Loc);<br>
+Â Â Â });<br>
+}<br>
+<br>
+static bool checkArrayDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ValueDecl *Src, QualType DecompType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const ConstantArrayType *CAT) {<br>
+Â return checkArrayLikeDecomposition(S, Bindings, Src, DecompType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â llvm::APSInt(CAT->getSize()),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â CAT->getElementType());<br>
+}<br>
+<br>
+static bool checkVectorDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ValueDecl *Src, QualType DecompType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const VectorType *VT) {<br>
+Â return checkArrayLikeDecomposition(<br>
+Â Â Â S, Bindings, Src, DecompType, llvm::APSInt::get(VT-><wbr>getNumElements()),<br>
+Â Â Â S.Context.getQualifiedType(VT-<wbr>>getElementType(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â DecompType.getQualifiers()));<br>
+}<br>
+<br>
+static bool checkComplexDecomposition(Sema &S,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ArrayRef<BindingDecl *> Bindings,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ValueDecl *Src, QualType DecompType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const ComplexType *CT) {<br>
+Â return checkSimpleDecomposition(<br>
+Â Â Â S, Bindings, Src, DecompType, llvm::APSInt::get(2),<br>
+Â Â Â S.Context.getQualifiedType(CT-<wbr>>getElementType(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â DecompType.getQualifiers()),<br>
+Â Â Â [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult {<br>
+Â Â Â Â return S.CreateBuiltinUnaryOp(Loc, I ? UO_Imag : UO_Real, Base);<br>
+Â Â Â });<br>
+}<br>
+<br>
+static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â TemplateArgumentListInfo &Args) {<br>
+Â SmallString<128> SS;<br>
+Â llvm::raw_svector_ostream OS(SS);<br>
+Â bool First = true;<br>
+Â for (auto &Arg : Args.arguments()) {<br>
+Â Â if (!First)<br>
+Â Â Â OS << ", ";<br>
+Â Â Arg.getArgument().print(<wbr>PrintingPolicy, OS);<br>
+Â Â First = false;<br>
+Â }<br>
+Â return OS.str();<br>
+}<br>
+<br>
+static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation Loc, StringRef Trait,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â TemplateArgumentListInfo &Args,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â unsigned DiagID) {<br>
+Â auto DiagnoseMissing = [&] {<br>
+Â Â if (DiagID)<br>
+Â Â Â S.Diag(Loc, DiagID) << printTemplateArgs(S.Context.<wbr>getPrintingPolicy(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Args);<br>
+Â Â return true;<br>
+Â };<br>
+<br>
+Â // FIXME: Factor out duplication with lookupPromiseType in SemaCoroutine.<br>
+Â NamespaceDecl *Std = S.getStdNamespace();<br>
+Â if (!Std)<br>
+Â Â return DiagnoseMissing();<br>
+<br>
+Â // Look up the trait itself, within namespace std. We can diagnose various<br>
+Â // problems with this lookup even if we've been asked to not diagnose a<br>
+Â // missing specialization, because this can only fail if the user has been<br>
+Â // declaring their own names in namespace std or we don't support the<br>
+Â // standard library implementation in use.<br>
+Â LookupResult Result(S, &S.PP.getIdentifierTable().<wbr>get(Trait),<br>
+Â Â Â Â Â Â Â Â Â Â Â Loc, Sema::LookupOrdinaryName);<br>
+Â if (!S.LookupQualifiedName(<wbr>Result, Std))<br>
+Â Â return DiagnoseMissing();<br>
+Â if (Result.isAmbiguous())<br>
+Â Â return true;<br>
+<br>
+Â ClassTemplateDecl *TraitTD = Result.getAsSingle<<wbr>ClassTemplateDecl>();<br>
+Â if (!TraitTD) {<br>
+Â Â Result.suppressDiagnostics();<br>
+Â Â NamedDecl *Found = *Result.begin();<br>
+Â Â S.Diag(Loc, diag::err_std_type_trait_not_<wbr>class_template) << Trait;<br>
+Â Â S.Diag(Found->getLocation(), diag::note_declared_at);<br>
+Â Â return true;<br>
+Â }<br>
+<br>
+Â // Build the template-id.<br>
+Â QualType TraitTy = S.CheckTemplateIdType(<wbr>TemplateName(TraitTD), Loc, Args);<br>
+Â if (TraitTy.isNull())<br>
+Â Â return true;<br>
+Â if (!S.isCompleteType(Loc, TraitTy)) {<br>
+Â Â if (DiagID)<br>
+Â Â Â S.RequireCompleteType(<br>
+Â Â Â Â Â Loc, TraitTy, DiagID,<br>
+Â Â Â Â Â printTemplateArgs(S.Context.<wbr>getPrintingPolicy(), Args));<br>
+Â Â return true;<br>
+Â }<br>
+<br>
+Â CXXRecordDecl *RD = TraitTy->getAsCXXRecordDecl();<br>
+Â assert(RD && "specialization of class template is not a class?");<br>
+<br>
+Â // Look up the member of the trait type.<br>
+Â S.LookupQualifiedName(<wbr>TraitMemberLookup, RD);<br>
+Â return TraitMemberLookup.isAmbiguous(<wbr>);<br>
+}<br>
+<br>
+static TemplateArgumentLoc<br>
+<wbr>getTrivialIntegralTemplateArgu<wbr>ment(Sema &S, SourceLocation Loc, QualType T,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â uint64_t I) {<br>
+Â TemplateArgument Arg(S.Context, S.Context.MakeIntValue(I, T), T);<br>
+Â return S.<wbr>getTrivialTemplateArgumentLoc(<wbr>Arg, T, Loc);<br>
+}<br>
+<br>
+static TemplateArgumentLoc<br>
+<wbr>getTrivialTypeTemplateArgument<wbr>(Sema &S, SourceLocation Loc, QualType T) {<br>
+Â return S.<wbr>getTrivialTemplateArgumentLoc(<wbr>TemplateArgument(T), QualType(), Loc);<br>
+}<br>
+<br>
+namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; }<br>
+<br>
+static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â llvm::APSInt &Size) {<br>
+Â EnterExpressionEvaluationConte<wbr>xt ContextRAII(S, Sema::ConstantEvaluated);<br>
+<br>
+Â DeclarationName Value = S.PP.getIdentifierInfo("value"<wbr>);<br>
+Â LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName);<br>
+<br>
+Â // Form template argument list for tuple_size<T>.<br>
+Â TemplateArgumentListInfo Args(Loc, Loc);<br>
+Â Args.addArgument(<wbr>getTrivialTypeTemplateArgument<wbr>(S, Loc, T));<br>
+<br>
+Â // If there's no tuple_size specialization, it's not tuple-like.<br>
+Â if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0))<br>
+Â Â return IsTupleLike::NotTupleLike;<br>
+<br>
+Â // FIXME: According to the standard, we're not supposed to diagnose if any<br>
+Â // of the steps below fail (or if lookup for ::value is ambiguous or otherwise<br>
+Â // results in an error), but this is subject to a pending CWG issue / NB<br>
+Â // comment, which says we do diagnose if tuple_size<T> is complete but<br>
+Â // tuple_size<T>::value is not an ICE.<br>
+<br>
+Â struct ICEDiagnoser : Sema::VerifyICEDiagnoser {<br>
+Â Â LookupResult &R;<br>
+Â Â TemplateArgumentListInfo &Args;<br>
+Â Â ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args)<br>
+Â Â Â Â : R(R), Args(Args) {}<br>
+Â Â void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {<br>
+Â Â Â S.Diag(Loc, diag::err_decomp_decl_std_<wbr>tuple_size_not_constant)<br>
+Â Â Â Â Â << printTemplateArgs(S.Context.<wbr>getPrintingPolicy(), Args);<br>
+Â Â }<br>
+Â } Diagnoser(R, Args);<br>
+<br>
+Â if (R.empty()) {<br>
+Â Â Diagnoser.diagnoseNotICE(S, Loc, SourceRange());<br>
+Â Â return IsTupleLike::Error;<br>
+Â }<br>
+<br>
+Â ExprResult E =<br>
+Â Â Â S.BuildDeclarationNameExpr(<wbr>CXXScopeSpec(), R, /*NeedsADL*/false);<br>
+Â if (E.isInvalid())<br>
+Â Â return IsTupleLike::Error;<br>
+<br>
+Â E = S.<wbr>VerifyIntegerConstantExpressio<wbr>n(E.get(), &Size, Diagnoser, false);<br>
+Â if (E.isInvalid())<br>
+Â Â return IsTupleLike::Error;<br>
+<br>
+Â return IsTupleLike::TupleLike;<br>
+}<br>
+<br>
+/// \return std::tuple_element<I, T>::type.<br>
+static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â unsigned I, QualType T) {<br>
+Â // Form template argument list for tuple_element<I, T>.<br>
+Â TemplateArgumentListInfo Args(Loc, Loc);<br>
+Â Args.addArgument(<br>
+Â Â Â getTrivialIntegralTemplateArgu<wbr>ment(S, Loc, S.Context.getSizeType(), I));<br>
+Â Args.addArgument(<wbr>getTrivialTypeTemplateArgument<wbr>(S, Loc, T));<br>
+<br>
+Â DeclarationName TypeDN = S.PP.getIdentifierInfo("type")<wbr>;<br>
+Â LookupResult R(S, TypeDN, Loc, Sema::LookupOrdinaryName);<br>
+Â if (lookupStdTypeTraitMember(<br>
+Â Â Â Â Â S, R, Loc, "tuple_element", Args,<br>
+Â Â Â Â Â diag::err_decomp_decl_std_<wbr>tuple_element_not_specialized)<wbr>)<br>
+Â Â return QualType();<br>
+<br>
+Â auto *TD = R.getAsSingle<TypeDecl>();<br>
+Â if (!TD) {<br>
+Â Â R.suppressDiagnostics();<br>
+Â Â S.Diag(Loc, diag::err_decomp_decl_std_<wbr>tuple_element_not_specialized)<br>
+Â Â Â << printTemplateArgs(S.Context.<wbr>getPrintingPolicy(), Args);<br>
+Â Â if (!R.empty())<br>
+Â Â Â S.Diag(R.<wbr>getRepresentativeDecl()-><wbr>getLocation(), diag::note_declared_at);<br>
+Â Â return QualType();<br>
+Â }<br>
+<br>
+Â return S.Context.getTypeDeclType(TD);<br>
+}<br>
+<br>
+namespace {<br>
+struct BindingDiagnosticTrap {<br>
+Â Sema &S;<br>
+Â DiagnosticErrorTrap Trap;<br>
+Â BindingDecl *BD;<br>
+<br>
+Â BindingDiagnosticTrap(Sema &S, BindingDecl *BD)<br>
+Â Â Â : S(S), Trap(S.Diags), BD(BD) {}<br>
+Â ~BindingDiagnosticTrap() {<br>
+Â Â if (Trap.hasErrorOccurred())<br>
+Â Â Â S.Diag(BD->getLocation(), diag::note_in_binding_decl_<wbr>init) << BD;<br>
+Â }<br>
+};<br>
+}<br>
+<br>
+static bool<br>
+checkTupleLikeDecomposition(<wbr>Sema &S, ArrayRef<BindingDecl *> Bindings,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â ValueDecl *Src, InitializedEntity &ParentEntity,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â QualType DecompType, llvm::APSInt TupleSize) {<br>
+Â if ((int64_t)Bindings.size() != TupleSize) {<br>
+Â Â S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_<wbr>number_bindings)<br>
+Â Â Â Â << DecompType << (unsigned)Bindings.size() << TupleSize.toString(10)<br>
+Â Â Â Â << (TupleSize < Bindings.size());<br>
+Â Â return true;<br>
+Â }<br>
+<br>
+Â if (Bindings.empty())<br>
+Â Â return false;<br>
+<br>
+Â DeclarationName GetDN = S.PP.getIdentifierInfo("get");<br>
+<br>
+Â // [dcl.decomp]p3:<br>
+Â //Â Â The unqualified-id get is looked up in the scope of E by class member<br>
+Â //Â Â access lookup<br>
+Â LookupResult MemberGet(S, GetDN, Src->getLocation(), Sema::LookupMemberName);<br>
+Â bool UseMemberGet = false;<br>
+Â if (S.isCompleteType(Src-><wbr>getLocation(), DecompType)) {<br>
+Â Â if (auto *RD = DecompType-><wbr>getAsCXXRecordDecl())<br>
+Â Â Â S.LookupQualifiedName(<wbr>MemberGet, RD);<br>
+Â Â if (MemberGet.isAmbiguous())<br>
+Â Â Â return true;<br>
+Â Â UseMemberGet = !MemberGet.empty();<br>
+Â Â S.<wbr>FilterAcceptableTemplateNames(<wbr>MemberGet);<br>
+Â }<br>
+<br>
+Â unsigned I = 0;<br>
+Â for (auto *B : Bindings) {<br>
+Â Â BindingDiagnosticTrap Trap(S, B);<br>
+Â Â SourceLocation Loc = B->getLocation();<br>
+<br>
+Â Â ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+<br>
+Â Â //Â Â e is an lvalue if the type of the entity is an lvalue reference and<br>
+Â Â //Â Â an xvalue otherwise<br>
+Â Â if (!Src->getType()-><wbr>isLValueReferenceType())<br>
+Â Â Â E = ImplicitCastExpr::Create(S.<wbr>Context, E.get()->getType(), CK_NoOp,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â E.get(), nullptr, VK_XValue);<br>
+<br>
+Â Â TemplateArgumentListInfo Args(Loc, Loc);<br>
+Â Â Args.addArgument(<br>
+Â Â Â Â getTrivialIntegralTemplateArgu<wbr>ment(S, Loc, S.Context.getSizeType(), I));<br>
+<br>
+Â Â if (UseMemberGet) {<br>
+Â Â Â //Â Â if [lookup of member get] finds at least one declaration, the<br>
+Â Â Â //Â Â initializer is e.get<i-1>().<br>
+Â Â Â E = S.BuildMemberReferenceExpr(E.<wbr>get(), DecompType, Loc, false,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â CXXScopeSpec(), SourceLocation(), nullptr,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â MemberGet, &Args, nullptr);<br>
+Â Â Â if (E.isInvalid())<br>
+Â Â Â Â return true;<br>
+<br>
+Â Â Â E = S.ActOnCallExpr(nullptr, E.get(), Loc, None, Loc);<br>
+Â Â } else {<br>
+Â Â Â //Â Â Otherwise, the initializer is get<i-1>(e), where get is looked up<br>
+Â Â Â //Â Â in the associated namespaces.<br>
+Â Â Â Expr *Get = UnresolvedLookupExpr::Create(<br>
+Â Â Â Â Â S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),<br>
+Â Â Â Â Â DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/true, &Args,<br>
+Â Â Â Â Â UnresolvedSetIterator(), UnresolvedSetIterator());<br>
+<br>
+Â Â Â Expr *Arg = E.get();<br>
+Â Â Â E = S.ActOnCallExpr(nullptr, Get, Loc, Arg, Loc);<br>
+Â Â }<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+Â Â Expr *Init = E.get();<br>
+<br>
+Â Â //Â Â Given the type T designated by std::tuple_element<i - 1, E>::type,<br>
+Â Â QualType T = getTupleLikeElementType(S, Loc, I, DecompType);<br>
+Â Â if (T.isNull())<br>
+Â Â Â return true;<br>
+<br>
+Â Â //Â Â each vi is a variable of type "reference to T" initialized with the<br>
+Â Â //Â Â initializer, where the reference is an lvalue reference if the<br>
+Â Â //Â Â initializer is an lvalue and an rvalue reference otherwise<br>
+Â Â QualType RefType =<br>
+Â Â Â Â S.BuildReferenceType(T, E.get()->isLValue(), Loc, B->getDeclName());<br>
+Â Â if (RefType.isNull())<br>
+Â Â Â return true;<br>
+<br>
+Â Â InitializedEntity Entity =<br>
+Â Â Â Â InitializedEntity::<wbr>InitializeBinding(<wbr>ParentEntity, B, RefType);<br>
+Â Â InitializationKind Kind = InitializationKind::<wbr>CreateCopy(Loc, Loc);<br>
+Â Â InitializationSequence Seq(S, Entity, Kind, Init);<br>
+Â Â E = Seq.Perform(S, Entity, Kind, Init);<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+<br>
+Â Â B->setBinding(T, E.get());<br>
+Â Â I++;<br>
+Â }<br>
+<br>
+Â return false;<br>
+}<br>
+<br>
+/// Find the base class to decompose in a built-in decomposition of a class type.<br>
+/// This base class search is, unfortunately, not quite like any other that we<br>
+/// perform anywhere else in C++.<br>
+static const CXXRecordDecl *findDecomposableBaseClass(<wbr>Sema &S,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation Loc,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const CXXRecordDecl *RD,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â CXXCastPath &BasePath) {<br>
+Â auto BaseHasFields = [](const CXXBaseSpecifier *Specifier,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â CXXBasePath &Path) {<br>
+Â Â return Specifier->getType()-><wbr>getAsCXXRecordDecl()-><wbr>hasDirectFields();<br>
+Â };<br>
+<br>
+Â const CXXRecordDecl *ClassWithFields = nullptr;<br>
+Â if (RD->hasDirectFields())<br>
+Â Â // [dcl.decomp]p4:<br>
+Â Â //Â Â Otherwise, all of E's non-static data members shall be public direct<br>
+Â Â //Â Â members of E ...<br>
+Â Â ClassWithFields = RD;<br>
+Â else {<br>
+Â Â //Â Â ... or of ...<br>
+Â Â CXXBasePaths Paths;<br>
+Â Â Paths.setOrigin(const_cast<<wbr>CXXRecordDecl*>(RD));<br>
+Â Â if (!RD->lookupInBases(<wbr>BaseHasFields, Paths)) {<br>
+Â Â Â // If no classes have fields, just decompose RD itself. (This will work<br>
+Â Â Â // if and only if zero bindings were provided.)<br>
+Â Â Â return RD;<br>
+Â Â }<br>
+<br>
+Â Â CXXBasePath *BestPath = nullptr;<br>
+Â Â for (auto &P : Paths) {<br>
+Â Â Â if (!BestPath)<br>
+Â Â Â Â BestPath = &P;<br>
+Â Â Â else if (!S.Context.hasSameType(P.<wbr>back().Base->getType(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â BestPath->back().Base-><wbr>getType())) {<br>
+Â Â Â Â //Â Â ... the same ...<br>
+Â Â Â Â S.Diag(Loc, diag::err_decomp_decl_<wbr>multiple_bases_with_members)<br>
+Â Â Â Â Â << false << RD << BestPath->back().Base-><wbr>getType()<br>
+Â Â Â Â Â << P.back().Base->getType();<br>
+Â Â Â Â return nullptr;<br>
+Â Â Â } else if (P.Access < BestPath->Access) {<br>
+Â Â Â Â BestPath = &P;<br>
+Â Â Â }<br>
+Â Â }<br>
+<br>
+Â Â //Â Â ... unambiguous ...<br>
+Â Â QualType BaseType = BestPath->back().Base-><wbr>getType();<br>
+Â Â if (Paths.isAmbiguous(S.Context.<wbr>getCanonicalType(BaseType))) {<br>
+Â Â Â S.Diag(Loc, diag::err_decomp_decl_<wbr>ambiguous_base)<br>
+Â Â Â Â << RD << BaseType << S.<wbr>getAmbiguousPathsDisplayString<wbr>(Paths);<br>
+Â Â Â return nullptr;<br>
+Â Â }<br>
+<br>
+Â Â //Â Â ... public base class of E.<br>
+Â Â if (BestPath->Access != AS_public) {<br>
+Â Â Â S.Diag(Loc, diag::err_decomp_decl_non_<wbr>public_base)<br>
+Â Â Â Â << RD << BaseType;<br>
+Â Â Â for (auto &BS : *BestPath) {<br>
+Â Â Â Â if (BS.Base->getAccessSpecifier() != AS_public) {<br>
+Â Â Â Â Â S.Diag(BS.Base->getLocStart(), diag::note_access_constrained_<wbr>by_path)<br>
+Â Â Â Â Â Â << (BS.Base->getAccessSpecifier() == AS_protected)<br>
+Â Â Â Â Â Â << (BS.Base-><wbr>getAccessSpecifierAsWritten() == AS_none);<br>
+Â Â Â Â Â break;<br>
+Â Â Â Â }<br>
+Â Â Â }<br>
+Â Â Â return nullptr;<br>
+Â Â }<br>
+<br>
+Â Â ClassWithFields = BaseType->getAsCXXRecordDecl()<wbr>;<br>
+Â Â S.BuildBasePathArray(Paths, BasePath);<br>
+Â }<br>
+<br>
+Â // The above search did not check whether the selected class itself has base<br>
+Â // classes with fields, so check that now.<br>
+Â CXXBasePaths Paths;<br>
+Â if (ClassWithFields-><wbr>lookupInBases(BaseHasFields, Paths)) {<br>
+Â Â S.Diag(Loc, diag::err_decomp_decl_<wbr>multiple_bases_with_members)<br>
+Â Â Â << (ClassWithFields == RD) << RD << ClassWithFields<br>
+Â Â Â << Paths.front().back().Base-><wbr>getType();<br>
+Â Â return nullptr;<br>
+Â }<br>
+<br>
+Â return ClassWithFields;<br>
+}<br>
+<br>
+static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ValueDecl *Src, QualType DecompType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const CXXRecordDecl *RD) {<br>
+Â CXXCastPath BasePath;<br>
+Â RD = findDecomposableBaseClass(S, Src->getLocation(), RD, BasePath);<br>
+Â if (!RD)<br>
+Â Â return true;<br>
+Â QualType BaseType = S.Context.getQualifiedType(S.<wbr>Context.getRecordType(RD),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â DecompType.getQualifiers());<br>
+<br>
+Â auto DiagnoseBadNumberOfBindings = [&]() -> bool {<br>
+Â Â unsigned NumFields = std::distance(RD->field_begin(<wbr>), RD->field_end());<br>
+Â Â assert(Bindings.size() != NumFields);<br>
+Â Â S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_<wbr>number_bindings)<br>
+Â Â Â Â << DecompType << (unsigned)Bindings.size() << NumFields<br>
+Â Â Â Â << (NumFields < Bindings.size());<br>
+Â Â return true;<br>
+Â };<br>
+<br>
+Â //Â Â all of E's non-static data members shall be public [...] members,<br>
+Â //Â Â E shall not have an anonymous union member, ...<br>
+Â unsigned I = 0;<br>
+Â for (auto *FD : RD->fields()) {<br>
+Â Â if (FD->isUnnamedBitfield())<br>
+Â Â Â continue;<br>
+<br>
+Â Â if (FD->isAnonymousStructOrUnion(<wbr>)) {<br>
+Â Â Â S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_<wbr>union_member)<br>
+Â Â Â Â << DecompType << FD->getType()->isUnionType();<br>
+Â Â Â S.Diag(FD->getLocation(), diag::note_declared_at);<br>
+Â Â Â return true;<br>
+Â Â }<br>
+<br>
+Â Â // We have a real field to bind.<br>
+Â Â if (I >= Bindings.size())<br>
+Â Â Â return DiagnoseBadNumberOfBindings();<br>
+Â Â auto *B = Bindings[I++];<br>
+<br>
+Â Â SourceLocation Loc = B->getLocation();<br>
+Â Â if (FD->getAccess() != AS_public) {<br>
+Â Â Â S.Diag(Loc, diag::err_decomp_decl_non_<wbr>public_member) << FD << DecompType;<br>
+<br>
+Â Â Â // Determine whether the access specifier was explicit.<br>
+Â Â Â bool Implicit = true;<br>
+Â Â Â for (const auto *D : RD->decls()) {<br>
+Â Â Â Â if (declaresSameEntity(D, FD))<br>
+Â Â Â Â Â break;<br>
+Â Â Â Â if (isa<AccessSpecDecl>(D)) {<br>
+Â Â Â Â Â Implicit = false;<br>
+Â Â Â Â Â break;<br>
+Â Â Â Â }<br>
+Â Â Â }<br>
+<br>
+Â Â Â S.Diag(FD->getLocation(), diag::note_access_natural)<br>
+Â Â Â Â << (FD->getAccess() == AS_protected) << Implicit;<br>
+Â Â Â return true;<br>
+Â Â }<br>
+<br>
+Â Â // Initialize the binding to Src.FD.<br>
+Â Â ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+Â Â E = S.ImpCastExprToType(E.get(), BaseType, CK_UncheckedDerivedToBase,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â VK_LValue, &BasePath);<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+Â Â E = S.BuildFieldReferenceExpr(E.<wbr>get(), /*IsArrow*/ false, Loc,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â CXXScopeSpec(), FD,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â DeclAccessPair::make(FD, FD->getAccess()),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â DeclarationNameInfo(FD-><wbr>getDeclName(), Loc));<br>
+Â Â if (E.isInvalid())<br>
+Â Â Â return true;<br>
+<br>
+Â Â // If the type of the member is T, the referenced type is cv T, where cv is<br>
+Â Â // the cv-qualification of the decomposition expression.<br>
+Â Â //<br>
+Â Â // FIXME: We resolve a defect here: if the field is mutable, we do not add<br>
+Â Â // 'const' to the type of the field.<br>
+Â Â Qualifiers Q = DecompType.getQualifiers();<br>
+Â Â if (FD->isMutable())<br>
+Â Â Â Q.removeConst();<br>
+Â Â B->setBinding(S.<wbr>BuildQualifiedType(FD-><wbr>getType(), Loc, Q), E.get());<br>
+Â }<br>
+<br>
+Â if (I != Bindings.size())<br>
+Â Â return DiagnoseBadNumberOfBindings();<br>
+<br>
+Â return false;<br>
+}<br>
+<br>
+void Sema::<wbr>CheckCompleteDecompositionDecl<wbr>aration(DecompositionDecl *DD,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â InitializedEntity &Entity) {<br>
+Â QualType DecompType = DD->getType();<br>
+<br>
+Â // If the type of the decomposition is dependent, then so is the type of<br>
+Â // each binding.<br>
+Â if (DecompType->isDependentType()<wbr>) {<br>
+Â Â for (auto *B : DD->bindings())<br>
+Â Â Â B->setType(Context.<wbr>DependentTy);<br>
+Â Â return;<br>
+Â }<br>
+<br>
+Â DecompType = DecompType.<wbr>getNonReferenceType();<br>
+Â ArrayRef<BindingDecl*> Bindings = DD->bindings();<br>
+<br>
+Â // C++1z [dcl.decomp]/2:<br>
+Â //Â Â If E is an array type [...]<br>
+Â // As an extension, we also support decomposition of built-in complex and<br>
+Â // vector types.<br>
+Â if (auto *CAT = Context.<wbr>getAsConstantArrayType(<wbr>DecompType)) {<br>
+Â Â if (checkArrayDecomposition(*<wbr>this, Bindings, DD, DecompType, CAT))<br>
+Â Â Â DD->setInvalidDecl();<br>
+Â Â return;<br>
+Â }<br>
+Â if (auto *VT = DecompType->getAs<VectorType>(<wbr>)) {<br>
+Â Â if (checkVectorDecomposition(*<wbr>this, Bindings, DD, DecompType, VT))<br>
+Â Â Â DD->setInvalidDecl();<br>
+Â Â return;<br>
+Â }<br>
+Â if (auto *CT = DecompType->getAs<ComplexType><wbr>()) {<br>
+Â Â if (checkComplexDecomposition(*<wbr>this, Bindings, DD, DecompType, CT))<br>
+Â Â Â DD->setInvalidDecl();<br>
+Â Â return;<br>
+Â }<br>
+<br>
+Â // C++1z [dcl.decomp]/3:<br>
+Â //Â Â if the expression std::tuple_size<E>::value is a well-formed integral<br>
+Â //Â Â constant expression, [...]<br>
+Â llvm::APSInt TupleSize(32);<br>
+Â switch (isTupleLike(*this, DD->getLocation(), DecompType, TupleSize)) {<br>
+Â case IsTupleLike::Error:<br>
+Â Â DD->setInvalidDecl();<br>
+Â Â return;<br>
+<br>
+Â case IsTupleLike::TupleLike:<br>
+Â Â if (checkTupleLikeDecomposition(*<wbr>this, Bindings, DD, Entity, DecompType,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â TupleSize))<br>
+Â Â Â DD->setInvalidDecl();<br>
+Â Â return;<br>
+<br>
+Â case IsTupleLike::NotTupleLike:<br>
+Â Â break;<br>
+Â }<br>
+<br>
+Â // C++1z [dcl.dcl]/8:<br>
+Â //Â Â [E shall be of array or non-union class type]<br>
+Â CXXRecordDecl *RD = DecompType-><wbr>getAsCXXRecordDecl();<br>
+Â if (!RD || RD->isUnion()) {<br>
+Â Â Diag(DD->getLocation(), diag::err_decomp_decl_<wbr>unbindable_type)<br>
+Â Â Â Â << DD << !RD << DecompType;<br>
+Â Â DD->setInvalidDecl();<br>
+Â Â return;<br>
+Â }<br>
+<br>
+Â // C++1z [dcl.decomp]/4:<br>
+Â //Â Â all of E's non-static data members shall be [...] direct members of<br>
+Â //Â Â E or of the same unambiguous public base class of E, ...<br>
+Â if (checkMemberDecomposition(*<wbr>this, Bindings, DD, DecompType, RD))<br>
+Â Â DD->setInvalidDecl();<br>
+}<br>
+<br>
 /// \brief Merge the exception specifications of two variable declarations.<br>
 ///<br>
 /// This is called when there's a redeclaration of a VarDecl. The function<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaExpr.cpp?rev=278435&r1=<wbr>278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaExpr.<wbr>cpp Thu Aug 11 17:25:46 2016<br>
@@ -1788,6 +1788,12 @@ Sema::BuildDeclRefExpr(<wbr>ValueDecl *D, Qua<br>
    E->setObjectKind(OK_BitField);<br>
  }<br>
<br>
+Â // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier<br>
+Â // designates a bit-field.<br>
+Â if (auto *BD = dyn_cast<BindingDecl>(D))<br>
+Â Â if (auto *BE = BD->getBinding())<br>
+Â Â Â E->setObjectKind(BE-><wbr>getObjectKind());<br>
+<br>
  return E;<br>
 }<br>
<br>
@@ -2943,7 +2949,6 @@ ExprResult Sema::BuildDeclarationNameExp<br>
   case Decl::<wbr>VarTemplateSpecialization:<br>
   case Decl::<wbr>VarTemplatePartialSpecializati<wbr>on:<br>
   case Decl::Decomposition:<br>
-Â Â case Decl::Binding:<br>
   case Decl::OMPCapturedExpr:<br>
    // In C, "extern void blah;" is valid and is an r-value.<br>
    if (!getLangOpts().CPlusPlus &&<br>
@@ -2971,6 +2976,14 @@ ExprResult Sema::BuildDeclarationNameExp<br>
<br>
    break;<br>
   }<br>
+<br>
+Â Â case Decl::Binding: {<br>
+Â Â Â // These are always lvalues.<br>
+Â Â Â valueKind = VK_LValue;<br>
+Â Â Â type = type.getNonReferenceType();<br>
+Â Â Â // FIXME: Adjust cv-qualifiers for capture.<br>
+Â Â Â break;<br>
+Â Â }<br>
<br>
   case Decl::Function: {<br>
    if (unsigned BID = cast<FunctionDecl>(VD)-><wbr>getBuiltinID()) {<br>
@@ -10580,7 +10593,8 @@ QualType Sema::CheckAddressOfOperand(<wbr>Exp<br>
      return MPTy;<br>
     }<br>
    }<br>
-Â Â } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(<wbr>dcl))<br>
+Â Â } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(<wbr>dcl) &&<br>
+Â Â Â Â Â Â Â Â !isa<BindingDecl>(dcl))<br>
    llvm_unreachable("Unknown/<wbr>unexpected decl type");<br>
  }<br>
<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaExprMember.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaExprMember.cpp?rev=278435&<wbr>r1=278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaExprMember.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaExprMember.cpp Thu Aug 11 17:25:46 2016<br>
@@ -771,12 +771,6 @@ Sema::<wbr>BuildMemberReferenceExpr(Expr *Bas<br>
                  false, ExtraArgs);<br>
 }<br>
<br>
-static ExprResult<br>
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation OpLoc, const CXXScopeSpec &SS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â FieldDecl *Field, DeclAccessPair FoundDecl,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â const DeclarationNameInfo &MemberNameInfo);<br>
-<br>
 ExprResult<br>
 Sema::<wbr>BuildAnonymousStructUnionMembe<wbr>rReference(const CXXScopeSpec &SS,<br>
                        SourceLocation loc,<br>
@@ -862,7 +856,7 @@ Sema::<wbr>BuildAnonymousStructUnionMembe<wbr>rRef<br>
   // Make a nameInfo that properly uses the anonymous name.<br>
   DeclarationNameInfo memberNameInfo(field-><wbr>getDeclName(), loc);<br>
<br>
-Â Â result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,<br>
+Â Â result = BuildFieldReferenceExpr(<wbr>result, baseObjectIsPointer,<br>
                   SourceLocation(), EmptySS, field,<br>
                   foundDecl, memberNameInfo).get();<br>
   if (!result)<br>
@@ -883,9 +877,10 @@ Sema::<wbr>BuildAnonymousStructUnionMembe<wbr>rRef<br>
     DeclAccessPair::make(field, field->getAccess());<br>
<br>
   result =<br>
-Â Â Â Â BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation(), (FI == FEnd ? SS : EmptySS),<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â field, fakeFoundDecl, memberNameInfo).get();<br>
+Â Â Â Â BuildFieldReferenceExpr(<wbr>result, /*isarrow*/ false, SourceLocation(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â (FI == FEnd ? SS : EmptySS), field,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â fakeFoundDecl, memberNameInfo)<br>
+Â Â Â Â Â Â .get();<br>
  }<br>
<br>
  return result;<br>
@@ -1153,8 +1148,8 @@ Sema::<wbr>BuildMemberReferenceExpr(Expr *Bas<br>
   return ExprError();<br>
<br>
  if (FieldDecl *FD = dyn_cast<FieldDecl>(<wbr>MemberDecl))<br>
-Â Â return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, OpLoc, SS, FD,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â FoundDecl, MemberNameInfo);<br>
+Â Â return BuildFieldReferenceExpr(<wbr>BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â MemberNameInfo);<br>
<br>
  if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(<wbr>MemberDecl))<br>
   return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,<br>
@@ -1757,11 +1752,11 @@ ExprResult Sema::ActOnMemberAccessExpr(S<br>
                  NameInfo, TemplateArgs, S, &ExtraArgs);<br>
 }<br>
<br>
-static ExprResult<br>
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation OpLoc, const CXXScopeSpec &SS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â FieldDecl *Field, DeclAccessPair FoundDecl,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â const DeclarationNameInfo &MemberNameInfo) {<br>
+ExprResult<br>
+Sema::<wbr>BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation OpLoc, const CXXScopeSpec &SS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â FieldDecl *Field, DeclAccessPair FoundDecl,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const DeclarationNameInfo &MemberNameInfo) {<br>
  // x.a is an l-value if 'a' has a reference type. Otherwise:<br>
  // x.a is an l-value/x-value/pr-value if the base is (and note<br>
  //  that *x is always an l-value), except that if the base isn't<br>
@@ -1795,36 +1790,34 @@ BuildFieldReferenceExpr(Sema &S, Expr *B<br>
   // except that 'mutable' members don't pick up 'const'.<br>
   if (Field->isMutable()) BaseQuals.removeConst();<br>
<br>
-Â Â Qualifiers MemberQuals<br>
-Â Â = S.Context.getCanonicalType(<wbr>MemberType).getQualifiers();<br>
+Â Â Qualifiers MemberQuals =<br>
+Â Â Â Â Context.getCanonicalType(<wbr>MemberType).getQualifiers();<br>
<br>
   assert(!MemberQuals.<wbr>hasAddressSpace());<br>
<br>
-<br>
   Qualifiers Combined = BaseQuals + MemberQuals;<br>
   if (Combined != MemberQuals)<br>
-Â Â Â MemberType = S.Context.getQualifiedType(<wbr>MemberType, Combined);<br>
+Â Â Â MemberType = Context.getQualifiedType(<wbr>MemberType, Combined);<br>
  }<br>
<br>
-Â S.UnusedPrivateFields.remove(<wbr>Field);<br>
+Â UnusedPrivateFields.remove(<wbr>Field);<br>
<br>
-Â ExprResult Base =<br>
-Â S.<wbr>PerformObjectMemberConversion(<wbr>BaseExpr, SS.getScopeRep(),<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â FoundDecl, Field);<br>
+Â ExprResult Base = PerformObjectMemberConversion(<wbr>BaseExpr, SS.getScopeRep(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â FoundDecl, Field);<br>
  if (Base.isInvalid())<br>
   return ExprError();<br>
  MemberExpr *ME =<br>
-Â Â Â BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,<br>
+Â Â Â BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,<br>
            /*TemplateKWLoc=*/<wbr>SourceLocation(), Field, FoundDecl,<br>
            MemberNameInfo, MemberType, VK, OK);<br>
<br>
  // Build a reference to a private copy for non-static data members in<br>
  // non-static member functions, privatized by OpenMP constructs.<br>
-Â if (S.getLangOpts().OpenMP && IsArrow &&<br>
-Â Â Â !S.CurContext-><wbr>isDependentContext() &&<br>
+Â if (getLangOpts().OpenMP && IsArrow &&<br>
+Â Â Â !CurContext-><wbr>isDependentContext() &&<br>
    isa<CXXThisExpr>(Base.get()-><wbr>IgnoreParenImpCasts())) {<br>
-Â Â if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field))<br>
-Â Â Â return S.getOpenMPCapturedExpr(<wbr>PrivateCopy, VK, OK, OpLoc);<br>
+Â Â if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field))<br>
+Â Â Â return getOpenMPCapturedExpr(<wbr>PrivateCopy, VK, OK, OpLoc);<br>
  }<br>
  return ME;<br>
 }<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaInit.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaInit.cpp?rev=278435&r1=<wbr>278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaInit.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaInit.<wbr>cpp Thu Aug 11 17:25:46 2016<br>
@@ -936,6 +936,7 @@ static void warnBracedScalarInit(Sema &S<br>
  case InitializedEntity::EK_Base:<br>
  case InitializedEntity::EK_<wbr>Delegating:<br>
  case InitializedEntity::EK_<wbr>BlockElement:<br>
+Â case InitializedEntity::EK_Binding:<br>
   llvm_unreachable("unexpected braced scalar init");<br>
  }<br>
<br>
@@ -2895,6 +2896,7 @@ DeclarationName InitializedEntity::getNa<br>
<br>
  case EK_Variable:<br>
  case EK_Member:<br>
+Â case EK_Binding:<br>
   return VariableOrMember->getDeclName(<wbr>);<br>
<br>
  case EK_LambdaCapture:<br>
@@ -2918,10 +2920,11 @@ DeclarationName InitializedEntity::getNa<br>
  llvm_unreachable("Invalid EntityKind!");<br>
 }<br>
<br>
-DeclaratorDecl *InitializedEntity::getDecl() const {<br>
+ValueDecl *InitializedEntity::getDecl() const {<br>
  switch (getKind()) {<br>
  case EK_Variable:<br>
  case EK_Member:<br>
+Â case EK_Binding:<br>
   return VariableOrMember;<br>
<br>
  case EK_Parameter:<br>
@@ -2957,6 +2960,7 @@ bool InitializedEntity::allowsNRVO(<wbr>) con<br>
  case EK_Parameter:<br>
  case EK_Parameter_CF_Audited:<br>
  case EK_Member:<br>
+Â case EK_Binding:<br>
  case EK_New:<br>
  case EK_Temporary:<br>
  case EK_CompoundLiteralInit:<br>
@@ -2988,6 +2992,7 @@ unsigned InitializedEntity::dumpImpl(<wbr>raw<br>
  case EK_Result: OS << "Result"; break;<br>
  case EK_Exception: OS << "Exception"; break;<br>
  case EK_Member: OS << "Member"; break;<br>
+Â case EK_Binding: OS << "Binding"; break;<br>
  case EK_New: OS << "New"; break;<br>
  case EK_Temporary: OS << "Temporary"; break;<br>
  case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;<br>
@@ -3004,9 +3009,9 @@ unsigned InitializedEntity::dumpImpl(<wbr>raw<br>
   break;<br>
  }<br>
<br>
-Â if (Decl *D = getDecl()) {<br>
+Â if (auto *D = getDecl()) {<br>
   OS << " ";<br>
-Â Â cast<NamedDecl>(D)-><wbr>printQualifiedName(OS);<br>
+Â Â D->printQualifiedName(OS);<br>
  }<br>
<br>
  OS << " '" << getType().getAsString() << "'\n";<br>
@@ -5270,6 +5275,7 @@ getAssignmentAction(const InitializedEnt<br>
   return Sema::AA_Casting;<br>
<br>
  case InitializedEntity::EK_Member:<br>
+Â case InitializedEntity::EK_Binding:<br>
  case InitializedEntity::EK_<wbr>ArrayElement:<br>
  case InitializedEntity::EK_<wbr>VectorElement:<br>
  case InitializedEntity::EK_<wbr>ComplexElement:<br>
@@ -5305,6 +5311,7 @@ static bool shouldBindAsTemporary(const<br>
  case InitializedEntity::EK_<wbr>Parameter_CF_Audited:<br>
  case InitializedEntity::EK_<wbr>Temporary:<br>
  case InitializedEntity::EK_<wbr>RelatedResult:<br>
+Â case InitializedEntity::EK_Binding:<br>
   return true;<br>
  }<br>
<br>
@@ -5326,6 +5333,7 @@ static bool shouldDestroyTemporary(const<br>
    return false;<br>
<br>
   case InitializedEntity::EK_Member:<br>
+Â Â case InitializedEntity::EK_Binding:<br>
   case InitializedEntity::EK_<wbr>Variable:<br>
   case InitializedEntity::EK_<wbr>Parameter:<br>
   case InitializedEntity::EK_<wbr>Parameter_CF_Audited:<br>
@@ -5395,6 +5403,7 @@ static SourceLocation getInitializationL<br>
   return Entity.getThrowLoc();<br>
<br>
  case InitializedEntity::EK_<wbr>Variable:<br>
+Â case InitializedEntity::EK_Binding:<br>
   return Entity.getDecl()->getLocation(<wbr>);<br>
<br>
  case InitializedEntity::EK_<wbr>LambdaCapture:<br>
@@ -5826,6 +5835,7 @@ InitializedEntityOutlivesFullE<wbr>xpression(<br>
  case InitializedEntity::EK_Result:<br>
  case InitializedEntity::EK_<wbr>Exception:<br>
  case InitializedEntity::EK_Member:<br>
+Â case InitializedEntity::EK_Binding:<br>
  case InitializedEntity::EK_New:<br>
  case InitializedEntity::EK_Base:<br>
  case InitializedEntity::EK_<wbr>Delegating:<br>
@@ -5875,6 +5885,9 @@ static const InitializedEntity *getEntit<br>
   //   ctor-initializer persists until the constructor exits.<br>
   return Entity;<br>
<br>
+Â case InitializedEntity::EK_Binding:<br>
+Â Â return getEntityForTemporaryLifetimeE<wbr>xtension(Entity->getParent(), nullptr);<br>
+<br>
  case InitializedEntity::EK_<wbr>Parameter:<br>
  case InitializedEntity::EK_<wbr>Parameter_CF_Audited:<br>
   //  -- A temporary bound to a reference parameter in a function call<br>
@@ -6250,7 +6263,7 @@ InitializationSequence::<wbr>Perform(Sema &S,<br>
      SourceRange Brackets;<br>
<br>
      // Scavange the location of the brackets from the entity, if we can.<br>
-Â Â Â Â Â if (DeclaratorDecl *DD = Entity.getDecl()) {<br>
+Â Â Â Â Â if (auto *DD = dyn_cast_or_null<<wbr>DeclaratorDecl>(Entity.<wbr>getDecl())) {<br>
       if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) {<br>
        TypeLoc TL = TInfo->getTypeLoc();<br>
        if (IncompleteArrayTypeLoc ArrayLoc =<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp?rev=278435&<wbr>r1=278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp Thu Aug 11 17:25:46 2016<br>
@@ -2073,11 +2073,8 @@ checkBuiltinTemplateIdType(<wbr>Sema &SemaRef<br>
   for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());<br>
     I < NumArgs; ++I) {<br>
    TemplateArgument TA(Context, I, ArgTy);<br>
-Â Â Â Expr *E = SemaRef.<wbr>BuildExpressionFromIntegralTem<wbr>plateArgument(<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â TA, TemplateArgs[2].getLocation())<br>
-Â Â Â Â Â Â Â Â Â Â .getAs<Expr>();<br>
-Â Â Â SyntheticTemplateArgs.<wbr>addArgument(<br>
-Â Â Â Â Â TemplateArgumentLoc(<wbr>TemplateArgument(E), E));<br>
+Â Â Â SyntheticTemplateArgs.<wbr>addArgument(SemaRef.<wbr>getTrivialTemplateArgumentLoc(<br>
+Â Â Â Â Â TA, ArgTy, TemplateArgs[2].getLocation())<wbr>);<br>
   }<br>
   // The first template argument will be reused as the template decl that<br>
   // our synthetic template arguments will be applied to.<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaTemplateDeduction.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaTemplateDeduction.cpp?rev=<wbr>278435&r1=278434&r2=278435&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaTemplateDeduction.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaTemplateDeduction.cpp Thu Aug 11 17:25:46 2016<br>
@@ -2002,37 +2002,33 @@ static bool isSameTemplateArg(ASTContext<br>
 ///<br>
 /// \param Loc The source location to use for the resulting template<br>
 /// argument.<br>
-static TemplateArgumentLoc<br>
-<wbr>getTrivialTemplateArgumentLoc(<wbr>Sema &S,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const TemplateArgument &Arg,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â QualType NTTPType,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â SourceLocation Loc) {<br>
+TemplateArgumentLoc<br>
+Sema::<wbr>getTrivialTemplateArgumentLoc(<wbr>const TemplateArgument &Arg,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â QualType NTTPType, SourceLocation Loc) {<br>
  switch (Arg.getKind()) {<br>
  case TemplateArgument::Null:<br>
   llvm_unreachable("Can't get a NULL template argument here");<br>
<br>
  case TemplateArgument::Type:<br>
-Â Â return TemplateArgumentLoc(Arg,<br>
-Â Â Â Â Â Â Â Â Â Â Â S.Context.<wbr>getTrivialTypeSourceInfo(Arg.<wbr>getAsType(), Loc));<br>
+Â Â return TemplateArgumentLoc(<br>
+Â Â Â Â Arg, Context.<wbr>getTrivialTypeSourceInfo(Arg.<wbr>getAsType(), Loc));<br>
<br>
  case TemplateArgument::Declaration: {<br>
-Â Â Expr *E<br>
-Â Â Â = S.<wbr>BuildExpressionFromDeclTemplat<wbr>eArgument(Arg, NTTPType, Loc)<br>
-Â Â Â Â Â .getAs<Expr>();<br>
+Â Â Expr *E = BuildExpressionFromDeclTemplat<wbr>eArgument(Arg, NTTPType, Loc)<br>
+Â Â Â Â Â Â Â Â Â .getAs<Expr>();<br>
   return TemplateArgumentLoc(<wbr>TemplateArgument(E), E);<br>
  }<br>
<br>
  case TemplateArgument::NullPtr: {<br>
-Â Â Expr *E<br>
-Â Â Â = S.<wbr>BuildExpressionFromDeclTemplat<wbr>eArgument(Arg, NTTPType, Loc)<br>
-Â Â Â Â Â .getAs<Expr>();<br>
+Â Â Expr *E = BuildExpressionFromDeclTemplat<wbr>eArgument(Arg, NTTPType, Loc)<br>
+Â Â Â Â Â Â Â Â Â .getAs<Expr>();<br>
   return TemplateArgumentLoc(<wbr>TemplateArgument(NTTPType, /*isNullPtr*/true),<br>
                E);<br>
  }<br>
<br>
  case TemplateArgument::Integral: {<br>
-Â Â Expr *E<br>
-Â Â Â = S.<wbr>BuildExpressionFromIntegralTem<wbr>plateArgument(Arg, Loc).getAs<Expr>();<br>
+Â Â Expr *E =<br>
+Â Â Â Â BuildExpressionFromIntegralTem<wbr>plateArgument(Arg, Loc).getAs<Expr>();<br>
   return TemplateArgumentLoc(<wbr>TemplateArgument(E), E);<br>
  }<br>
<br>
@@ -2041,18 +2037,16 @@ getTrivialTemplateArgumentLoc(<wbr>Sema &S,<br>
    NestedNameSpecifierLocBuilder Builder;<br>
    TemplateName Template = Arg.getAsTemplate();<br>
    if (DependentTemplateName *DTN = Template.<wbr>getAsDependentTemplateName())<br>
-Â Â Â Â Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc);<br>
+Â Â Â Â Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);<br>
    else if (QualifiedTemplateName *QTN =<br>
          Template.<wbr>getAsQualifiedTemplateName())<br>
-Â Â Â Â Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc);<br>
+Â Â Â Â Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);<br>
<br>
    if (Arg.getKind() == TemplateArgument::Template)<br>
-Â Â Â Â return TemplateArgumentLoc(Arg,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Builder.getWithLocInContext(S.<wbr>Context),<br>
+Â Â Â Â return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(<wbr>Context),<br>
                  Loc);<br>
-<br>
-<br>
-Â Â Â return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.<wbr>Context),<br>
+<br>
+Â Â Â return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(<wbr>Context),<br>
                 Loc, Loc);<br>
   }<br>
<br>
@@ -2100,7 +2094,7 @@ ConvertDeducedTemplateArgument<wbr>(Sema &S,<br>
   // argument that we can check, almost as if the user had written<br>
   // the template argument explicitly.<br>
   TemplateArgumentLoc ArgLoc =<br>
-Â Â Â Â getTrivialTemplateArgumentLoc(<wbr>S, Arg, NTTPType, Info.getLocation());<br>
+Â Â Â Â S.<wbr>getTrivialTemplateArgumentLoc(<wbr>Arg, NTTPType, Info.getLocation());<br>
<br>
   // Check the template argument, converting it as necessary.<br>
   return S.CheckTemplateArgument(<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaType.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaType.cpp?rev=278435&r1=<wbr>278434&r2=278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaType.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaType.<wbr>cpp Thu Aug 11 17:25:46 2016<br>
@@ -1748,6 +1748,12 @@ QualType Sema::BuildQualifiedType(<wbr>QualTy<br>
  if (T.isNull())<br>
   return QualType();<br>
<br>
+Â // Ignore any attempt to form a cv-qualified reference.<br>
+Â if (T->isReferenceType()) {<br>
+Â Â Qs.removeConst();<br>
+Â Â Qs.removeVolatile();<br>
+Â }<br>
+<br>
  // Enforce C99 6.7.3p2: "Types other than pointer types derived from<br>
  // object or incomplete types shall not be restrict-qualified."<br>
  if (Qs.hasRestrict()) {<br>
@@ -1789,6 +1795,11 @@ QualType Sema::BuildQualifiedType(<wbr>QualTy<br>
  if (T.isNull())<br>
   return QualType();<br>
<br>
+Â // Ignore any attempt to form a cv-qualified reference.<br>
+Â if (T->isReferenceType())<br>
+Â Â CVRAU &=<br>
+Â Â Â Â ~(DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic);<br>
+<br>
  // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and<br>
  // TQ_unaligned;<br>
  unsigned CVR = CVRAU & ~(DeclSpec::TQ_atomic | DeclSpec::TQ_unaligned);<br>
<br>
Added: cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p2.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp?rev=278435&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>dcl.decl/dcl.decomp/p2.cpp?<wbr>rev=278435&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p2.cpp (added)<br>
+++ cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p2.cpp Thu Aug 11 17:25:46 2016<br>
@@ -0,0 +1,22 @@<br>
+// RUN: %clang_cc1 -std=c++1z -verify %s<br>
+<br>
+int array() {<br>
+Â int arr[3] = {};<br>
+Â // FIXME: We are supposed to create an array object here and perform elementwise initialization.<br>
+Â auto [a, b, c] = arr; // expected-error {{cannot decompose non-class, non-array}}<br>
+<br>
+Â auto &[d, e] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but only 2 names were provided}}<br>
+Â auto &[f, g, h, i] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but 4 names were provided}}<br>
+<br>
+Â auto &[r0, r1, r2] = arr;<br>
+Â const auto &[cr0, cr1, cr2] = arr;<br>
+<br>
+Â //static_assert(&arr[0] == &r0);<br>
+Â //static_assert(&arr[0] == &cr0);<br>
+Â using T = int;<br>
+Â using T = decltype(r0);<br>
+Â using U = const int;<br>
+Â using U = decltype(cr0);<br>
+<br>
+Â return r1 + cr2;<br>
+}<br>
<br>
Added: cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p3.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp?rev=278435&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>dcl.decl/dcl.decomp/p3.cpp?<wbr>rev=278435&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p3.cpp (added)<br>
+++ cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p3.cpp Thu Aug 11 17:25:46 2016<br>
@@ -0,0 +1,203 @@<br>
+// RUN: %clang_cc1 -std=c++1z -verify %s<br>
+<br>
+using size_t = decltype(sizeof(0));<br>
+<br>
+struct A { int x, y; };<br>
+struct B { int x, y; };<br>
+<br>
+void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise<br>
+<br>
+namespace std { template<typename T> struct tuple_size; }<br>
+void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise<br>
+<br>
+struct Bad1 {};<br>
+template<> struct std::tuple_size<Bad1> {};<br>
+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}}<br>
+<br>
+struct Bad2 {};<br>
+template<> struct std::tuple_size<Bad2> { const int value = 5; };<br>
+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}}<br>
+<br>
+template<> struct std::tuple_size<A> { static const int value = 3; };<br>
+template<> struct std::tuple_size<B> { enum { value = 3 }; };<br>
+<br>
+void no_get_1() {<br>
+Â {<br>
+Â Â auto [a0, a1] = A(); // expected-error {{decomposes into 3 elements}}<br>
+Â Â auto [b0, b1] = B(); // expected-error {{decomposes into 3 elements}}<br>
+Â }<br>
+Â auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}}<br>
+}<br>
+<br>
+int get(A);<br>
+<br>
+void no_get_2() {<br>
+Â // FIXME: This diagnostic is not great.<br>
+Â auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}}<br>
+}<br>
+<br>
+template<int> float &get(A);<br>
+<br>
+void no_tuple_element_1() {<br>
+Â auto [a0, a1, a2] = A(); // expected-error-re {{'std::tuple_element<0U{{L*}}<wbr>, A>::type' does not name a type}} expected-note {{in implicit}}<br>
+}<br>
+<br>
+namespace std { template<size_t, typename> struct tuple_element; } // expected-note 2{{here}}<br>
+<br>
+void no_tuple_element_2() {<br>
+Â auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<0, A>'}} expected-note {{in implicit}}<br>
+}<br>
+<br>
+template<> struct std::tuple_element<0, A> { typedef float type; };<br>
+<br>
+void no_tuple_element_3() {<br>
+Â auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<1, A>'}} expected-note {{in implicit}}<br>
+}<br>
+<br>
+template<> struct std::tuple_element<1, A> { typedef float &type; };<br>
+template<> struct std::tuple_element<2, A> { typedef const float &type; };<br>
+<br>
+template<int N> auto get(B) -> int (&)[N + 1];<br>
+template<int N> struct std::tuple_element<N, B> { typedef int type[N +1 ]; };<br>
+<br>
+template<typename T> struct std::tuple_size<const T> : std::tuple_size<T> {};<br>
+template<size_t N, typename T> struct std::tuple_element<N, const T> {<br>
+Â typedef const typename std::tuple_element<N, T>::type type;<br>
+};<br>
+<br>
+void referenced_type() {<br>
+Â auto [a0, a1, a2] = A();<br>
+Â auto [b0, b1, b2] = B();<br>
+<br>
+Â A a;<br>
+Â B b;<br>
+Â auto &[ar0, ar1, ar2] = a;<br>
+Â auto &[br0, br1, br2] = b;<br>
+<br>
+Â auto &&[arr0, arr1, arr2] = A();<br>
+Â auto &&[brr0, brr1, brr2] = B();<br>
+<br>
+Â const auto &[acr0, acr1, acr2] = A();<br>
+Â const auto &[bcr0, bcr1, bcr2] = B();<br>
+<br>
+<br>
+Â using Float = float;<br>
+Â using Float = decltype(a0);<br>
+Â using Float = decltype(ar0);<br>
+Â using Float = decltype(arr0);<br>
+<br>
+Â using ConstFloat = const float;<br>
+Â using ConstFloat = decltype(acr0);<br>
+<br>
+Â using FloatRef = float&;<br>
+Â using FloatRef = decltype(a1);<br>
+Â using FloatRef = decltype(ar1);<br>
+Â using FloatRef = decltype(arr1);<br>
+Â using FloatRef = decltype(acr1);<br>
+<br>
+Â using ConstFloatRef = const float&;<br>
+Â using ConstFloatRef = decltype(a2);<br>
+Â using ConstFloatRef = decltype(ar2);<br>
+Â using ConstFloatRef = decltype(arr2);<br>
+Â using ConstFloatRef = decltype(acr2);<br>
+<br>
+<br>
+Â using Int1 = int[1];<br>
+Â using Int1 = decltype(b0);<br>
+Â using Int1 = decltype(br0);<br>
+Â using Int1 = decltype(brr0);<br>
+<br>
+Â using ConstInt1 = const int[1];<br>
+Â using ConstInt1 = decltype(bcr0);<br>
+<br>
+Â using Int2 = int[2];<br>
+Â using Int2 = decltype(b1);<br>
+Â using Int2 = decltype(br1);<br>
+Â using Int2 = decltype(brr1);<br>
+<br>
+Â using ConstInt2 = const int[2];<br>
+Â using ConstInt2 = decltype(bcr1);<br>
+<br>
+Â using Int3 = int[3];<br>
+Â using Int3 = decltype(b2);<br>
+Â using Int3 = decltype(br2);<br>
+Â using Int3 = decltype(brr2);<br>
+<br>
+Â using ConstInt3 = const int[3];<br>
+Â using ConstInt3 = decltype(bcr2);<br>
+}<br>
+<br>
+struct C { template<int> int get(); };<br>
+template<> struct std::tuple_size<C> { static const int value = 1; };<br>
+template<> struct std::tuple_element<0, C> { typedef int type; };<br>
+<br>
+int member_get() {<br>
+Â auto [c] = C();<br>
+Â using T = int;<br>
+Â using T = decltype(c);<br>
+Â return c;<br>
+}<br>
+<br>
+struct D { template<int> struct get {}; }; // expected-note {{declared here}}<br>
+template<> struct std::tuple_size<D> { static const int value = 1; };<br>
+template<> struct std::tuple_element<0, D> { typedef D::get<0> type; };<br>
+void member_get_class_template() {<br>
+Â auto [d] = D(); // expected-error {{cannot refer to member 'get' in 'D' with '.'}} expected-note {{in implicit init}}<br>
+}<br>
+<br>
+struct E { int get(); };<br>
+template<> struct std::tuple_size<E> { static const int value = 1; };<br>
+template<> struct std::tuple_element<0, E> { typedef int type; };<br>
+void member_get_non_template() {<br>
+Â // FIXME: This diagnostic is not very good.<br>
+Â auto [e] = E(); // expected-error {{no member named 'get'}} expected-note {{in implicit init}}<br>
+}<br>
+<br>
+namespace ADL {<br>
+Â struct X {};<br>
+};<br>
+template<int> int get(ADL::X);<br>
+template<> struct std::tuple_size<ADL::X> { static const int value = 1; };<br>
+template<> struct std::tuple_element<0, ADL::X> { typedef int type; };<br>
+void adl_only_bad() {<br>
+Â auto [x] = ADL::X(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit init}}<br>
+}<br>
+<br>
+template<typename ElemType, typename GetTypeLV, typename GetTypeRV><br>
+struct wrap {<br>
+Â template<size_t> GetTypeLV get() &;<br>
+Â template<size_t> GetTypeRV get() &&;<br>
+};<br>
+template<typename ET, typename GTL, typename GTR><br>
+struct std::tuple_size<wrap<ET, GTL, GTR>> {<br>
+Â static const int value = 1;<br>
+};<br>
+template<typename ET, typename GTL, typename GTR><br>
+struct std::tuple_element<0, wrap<ET, GTL, GTR>> {<br>
+Â using type = ET;<br>
+};<br>
+<br>
+template<typename T> T &lvalue();<br>
+<br>
+void test_value_category() {<br>
+Â // If the declared variable is an lvalue reference, the operand to get is an<br>
+Â // lvalue. Otherwise it's an xvalue.<br>
+Â { auto [a] = wrap<int, void, int>(); }<br>
+Â { auto &[a] = lvalue<wrap<int, int, void>>(); }<br>
+Â { auto &&[a] = wrap<int, void, int>(); }<br>
+Â // If the initializer (call to get) is an lvalue, the binding is an lvalue<br>
+Â // reference to the element type. Otherwise it's an rvalue reference to the<br>
+Â // element type.<br>
+Â { auto [a] = wrap<int, void, int&>(); }<br>
+Â { auto [a] = wrap<int&, void, int&>(); }<br>
+Â { auto [a] = wrap<int&&, void, int&>(); } // ok, reference collapse to int&<br>
+<br>
+Â { auto [a] = wrap<int, void, int&&>(); }<br>
+Â { auto [a] = wrap<int&, void, int&&>(); } // expected-error {{non-const lvalue reference to type 'int' cannot bind}} expected-note {{in implicit}}<br>
+Â { auto [a] = wrap<const int&, void, int&&>(); }<br>
+Â { auto [a] = wrap<int&&, void, int&&>(); }<br>
+<br>
+Â { auto [a] = wrap<int, void, float&>(); } // expected-error {{cannot bind}} expected-note {{implicit}}<br>
+Â { auto [a] = wrap<const int, void, float&>(); } // ok, const int &a can bind to float<br>
+Â { auto [a] = wrap<int, void, float>(); } // ok, int &&a can bind to float<br>
+}<br>
<br>
Added: cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p4.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp?rev=278435&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/CXX/<wbr>dcl.decl/dcl.decomp/p4.cpp?<wbr>rev=278435&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p4.cpp (added)<br>
+++ cfe/trunk/test/CXX/dcl.decl/<wbr>dcl.decomp/p4.cpp Thu Aug 11 17:25:46 2016<br>
@@ -0,0 +1,173 @@<br>
+// RUN: %clang_cc1 -std=c++1z -verify -triple i686-linux-gnu %s<br>
+<br>
+template<typename T, typename U> struct same;<br>
+template<typename T> struct same<T, T> { ~same(); };<br>
+<br>
+struct Empty {};<br>
+<br>
+struct A {<br>
+Â int a;<br>
+};<br>
+<br>
+namespace NonPublicMembers {<br>
+Â struct NonPublic1 {<br>
+Â protected:<br>
+Â Â int a; // expected-note {{declared protected here}}<br>
+Â };<br>
+<br>
+Â struct NonPublic2 {<br>
+Â private:<br>
+Â Â int a; // expected-note 2{{declared private here}}<br>
+Â };<br>
+<br>
+Â struct NonPublic3 : private A {}; // expected-note {{constrained by private inheritance}}<br>
+<br>
+Â struct NonPublic4 : NonPublic2 {};<br>
+<br>
+Â void test() {<br>
+Â Â auto [a1] = NonPublic1(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic1'<wbr>}}<br>
+Â Â auto [a2] = NonPublic2(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic2'<wbr>}}<br>
+Â Â auto [a3] = NonPublic3(); // expected-error {{cannot decompose members of non-public base class 'A' of 'NonPublic3'}}<br>
+Â Â auto [a4] = NonPublic4(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic4'<wbr>}}<br>
+Â }<br>
+}<br>
+<br>
+namespace MultipleClasses {<br>
+Â struct B : A {<br>
+Â Â int a;<br>
+Â };<br>
+<br>
+Â struct C { int a; };<br>
+Â struct D : A, C {};<br>
+<br>
+Â struct E : virtual A {};<br>
+Â struct F : A, E {}; // expected-warning {{direct base 'A' is inaccessible due to ambiguity}}<br>
+<br>
+Â struct G : virtual A {};<br>
+Â struct H : E, G {};<br>
+<br>
+Â struct I { int i; };<br>
+Â struct J : I {};<br>
+Â struct K : I, virtual J {}; // expected-warning {{direct base 'MultipleClasses::I' is inaccessible due to ambiguity}}<br>
+<br>
+Â struct L : virtual J {};<br>
+Â struct M : virtual J, L {};<br>
+<br>
+Â void test() {<br>
+Â Â auto [b] = B(); // expected-error {{cannot decompose class type 'B': both it and its base class 'A' have non-static data members}}<br>
+Â Â auto [d] = D(); // expected-error {{cannot decompose class type 'D': its base classes 'A' and 'MultipleClasses::C' have non-static data members}}<br>
+Â Â auto [e] = E();<br>
+Â Â 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}}<br>
+Â Â auto [h] = H(); // ok, only one (virtual) base subobject even though there are two paths to it<br>
+Â Â auto [k] = K(); // expected-error {{cannot decompose members of ambiguous base class 'MultipleClasses::I'}}<br>
+Â Â auto [m] = M(); // ok, all paths to I are through the same virtual base subobject J<br>
+<br>
+Â Â same<decltype(m), int>();<br>
+Â }<br>
+}<br>
+<br>
+namespace BindingTypes {<br>
+Â struct A {<br>
+Â Â int i = 0;<br>
+Â Â int &r = i;<br>
+Â Â const float f = i;<br>
+Â Â mutable volatile int mvi;<br>
+Â };<br>
+Â void e() {<br>
+Â Â auto [i,r,f,mvi] = A();<br>
+<br>
+Â Â same<decltype(i), int>();<br>
+Â Â same<decltype(r), int&>();<br>
+Â Â same<decltype(f), const float>();<br>
+Â Â same<decltype(mvi), volatile int>();<br>
+<br>
+Â Â same<decltype((i)), int&>();<br>
+Â Â same<decltype((r)), int&>();<br>
+Â Â same<decltype((f)), const float&>();<br>
+Â Â same<decltype((mvi)), volatile int&>();<br>
+Â }<br>
+Â void f() {<br>
+Â Â auto &&[i,r,f,mvi] = A();<br>
+<br>
+Â Â same<decltype(i), int>();<br>
+Â Â same<decltype(r), int&>();<br>
+Â Â same<decltype(f), const float>();<br>
+Â Â same<decltype(mvi), volatile int>();<br>
+<br>
+Â Â same<decltype((i)), int&>();<br>
+Â Â same<decltype((r)), int&>();<br>
+Â Â same<decltype((f)), const float&>();<br>
+Â Â same<decltype((mvi)), volatile int&>();<br>
+Â }<br>
+Â void g() {<br>
+Â Â const auto [i,r,f,mvi] = A();<br>
+<br>
+Â Â same<decltype(i), const int>();<br>
+Â Â same<decltype(r), int&>();<br>
+Â Â same<decltype(f), const float>();<br>
+Â Â same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx<br>
+<br>
+Â Â same<decltype((i)), const int&>();<br>
+Â Â same<decltype((r)), int&>();<br>
+Â Â same<decltype((f)), const float&>();<br>
+Â Â same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx<br>
+Â }<br>
+Â void h() {<br>
+Â Â typedef const A CA;<br>
+Â Â auto &[i,r,f,mvi] = CA(); // type of var is 'const A &'<br>
+<br>
+Â Â same<decltype(i), const int>(); // not 'int', per expected resolution of DRxxx<br>
+Â Â same<decltype(r), int&>();<br>
+Â Â same<decltype(f), const float>();<br>
+Â Â same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx<br>
+<br>
+Â Â same<decltype((i)), const int&>(); // not 'int&', per expected resolution of DRxxx<br>
+Â Â same<decltype((r)), int&>();<br>
+Â Â same<decltype((f)), const float&>();<br>
+Â Â same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx<br>
+Â }<br>
+Â struct B {<br>
+Â Â mutable int i;<br>
+Â };<br>
+Â void mut() {<br>
+Â Â auto [i] = B();<br>
+Â Â const auto [ci] = B();<br>
+Â Â volatile auto [vi] = B();<br>
+Â Â same<decltype(i), int>();<br>
+Â Â same<decltype(ci), int>();<br>
+Â Â same<decltype(vi), volatile int>();<br>
+Â }<br>
+}<br>
+<br>
+namespace Bitfield {<br>
+Â struct S { unsigned long long x : 4, y : 32; int z; }; // expected-note 2{{here}}<br>
+Â int f(S s) {<br>
+Â Â auto [a, b, c] = s;<br>
+Â Â unsigned long long &ra = a; // expected-error {{bit-field 'x'}}<br>
+Â Â unsigned long long &rb = b; // expected-error {{bit-field 'y'}}<br>
+Â Â int &rc = c;<br>
+<br>
+Â Â // the type of the binding is the type of the field<br>
+Â Â same<decltype(a), unsigned long long>();<br>
+Â Â same<decltype(b), unsigned long long>();<br>
+<br>
+Â Â // the type of the expression is an lvalue of the field type<br>
+Â Â // (even though a reference can't bind to the field)<br>
+Â Â same<decltype((a)), unsigned long long&>();<br>
+Â Â same<decltype((b)), unsigned long long&>();<br>
+<br>
+Â Â // the expression promotes to a type large enough to hold the result<br>
+Â Â same<decltype(+a), int>();<br>
+Â Â same<decltype(+b), unsigned int>();<br>
+Â Â return rc;<br>
+Â }<br>
+}<br>
+<br>
+namespace std_example {<br>
+Â struct S { int x1 : 2; volatile double y1; };<br>
+Â S f();<br>
+Â const auto [x, y] = f();<br>
+<br>
+Â same<decltype((x)), const int&> same1;<br>
+Â same<decltype((y)), const volatile double&> same2;<br>
+}<br>
<br>
Modified: cfe/trunk/test/Parser/cxx1z-<wbr>decomposition.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/Parser/<wbr>cxx1z-decomposition.cpp?rev=<wbr>278435&r1=278434&r2=278435&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/Parser/cxx1z-<wbr>decomposition.cpp (original)<br>
+++ cfe/trunk/test/Parser/cxx1z-<wbr>decomposition.cpp Thu Aug 11 17:25:46 2016<br>
@@ -67,7 +67,7 @@ namespace BadSpecifiers {<br>
   // storage-class-specifiers<br>
   static auto &[a] = n; // expected-error {{cannot be declared 'static'}}<br>
   thread_local auto &[b] = n; // expected-error {{cannot be declared 'thread_local'}}<br>
-Â Â extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}}<br>
+Â Â extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}}<br>
   struct S {<br>
    mutable auto &[d] = n; // expected-error {{not permitted in this context}}<br>
<br>
@@ -97,7 +97,7 @@ namespace BadSpecifiers {<br>
   auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}}<br>
<br>
   // FIXME: This should fire the 'misplaced array declarator' diagnostic.<br>
-Â Â int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}}<br>
+Â Â int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}}<br>
   int [5] arr = {0}; // expected-error {{place the brackets after the name}}<br>
<br>
   auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}}<br>
@@ -133,3 +133,16 @@ namespace Template {<br>
  // FIXME: There's no actual rule against this...<br>
  template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}}<br>
 }<br>
+<br>
+namespace Init {<br>
+Â void f() {<br>
+Â Â int arr[1];<br>
+Â Â struct S { int n; };<br>
+Â Â auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}}<br>
+Â Â const auto &[bad2](S{}); // expected-error {{decomposition declaration '[bad2]' cannot have a parenthesized initializer}}<br>
+Â Â auto &[good1] = arr;<br>
+Â Â auto &&[good2] = S{};<br>
+Â Â S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}}<br>
+Â Â S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}}<br>
+Â }<br>
+}<br>
<br>
Modified: cfe/trunk/test/SemaCXX/cxx1z-<wbr>decomposition.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>SemaCXX/cxx1z-decomposition.<wbr>cpp?rev=278435&r1=278434&r2=<wbr>278435&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/SemaCXX/cxx1z-<wbr>decomposition.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/cxx1z-<wbr>decomposition.cpp Thu Aug 11 17:25:46 2016<br>
@@ -4,7 +4,23 @@ void use_from_own_init() {<br>
  auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}}<br>
 }<br>
<br>
-// FIXME: create correct bindings<br>
+// As a Clang extension, _Complex can be decomposed.<br>
+float decompose_complex(_Complex float cf) {<br>
+Â auto [re, im] = cf;<br>
+Â //static_assert(&re == &__real cf);<br>
+Â //static_assert(&im == &__imag cf);<br>
+Â return re*re + im*im;<br>
+}<br>
+<br>
+// As a Clang extension, vector types can be decomposed.<br>
+typedef float vf3 __attribute__((ext_vector_<wbr>type(3)));<br>
+float decompose_vector(vf3 v) {<br>
+Â auto [x, y, z] = v;<br>
+Â auto *p = &x; // expected-error {{address of vector element requested}}<br>
+Â return x + y + z;<br>
+}<br>
+<br>
+// FIXME: by-value array copies<br>
 // FIXME: template instantiation<br>
 // FIXME: ast file support<br>
 // FIXME: code generation<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>