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

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 11 15:25:47 PDT 2016


Author: rsmith
Date: Thu Aug 11 17:25:46 2016
New Revision: 278435

URL: http://llvm.org/viewvc/llvm-project?rev=278435&view=rev
Log:
P0217R3: Perform semantic checks and initialization for the bindings in a
decomposition declaration for arrays, aggregate-like structs, tuple-like
types, and (as an extension) for complex and vector types.

Added:
    cfe/trunk/test/CXX/dcl.decl/dcl.decomp/
    cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp
Modified:
    cfe/trunk/include/clang/AST/CXXInheritance.h
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/AST/UnresolvedSet.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Initialization.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTDumper.cpp
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprClassification.cpp
    cfe/trunk/lib/Sema/Sema.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprMember.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/Parser/cxx1z-decomposition.cpp
    cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp

Modified: cfe/trunk/include/clang/AST/CXXInheritance.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CXXInheritance.h?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/CXXInheritance.h (original)
+++ cfe/trunk/include/clang/AST/CXXInheritance.h Thu Aug 11 17:25:46 2016
@@ -172,7 +172,7 @@ public:
   /// paths for a derived-to-base search.
   explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths = true,
                         bool DetectVirtual = true)
-      : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
+      : Origin(), FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
         DetectVirtual(DetectVirtual), DetectedVirtual(nullptr),
         NumDeclsFound(0) {}
 

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Aug 11 17:25:46 2016
@@ -251,7 +251,7 @@ public:
   // FIXME: Deprecated, move clients to getName().
   std::string getNameAsString() const { return Name.getAsString(); }
 
-  void printName(raw_ostream &os) const { os << Name; }
+  virtual void printName(raw_ostream &os) const;
 
   /// getDeclName - Get the actual, stored name of the declaration,
   /// which may be a special name.
@@ -1025,7 +1025,7 @@ public:
   ///   void foo() { int x; static int y; extern int z; }
   ///
   bool isLocalVarDecl() const {
-    if (getKind() != Decl::Var)
+    if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
       return false;
     if (const DeclContext *DC = getLexicalDeclContext())
       return DC->getRedeclContext()->isFunctionOrMethod();
@@ -1040,7 +1040,7 @@ public:
   /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but
   /// excludes variables declared in blocks.
   bool isFunctionOrMethodVarDecl() const {
-    if (getKind() != Decl::Var)
+    if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
       return false;
     const DeclContext *DC = getLexicalDeclContext()->getRedeclContext();
     return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Aug 11 17:25:46 2016
@@ -1147,6 +1147,12 @@ public:
   /// \note This does NOT include a check for union-ness.
   bool isEmpty() const { return data().Empty; }
 
+  /// \brief Determine whether this class has direct non-static data members.
+  bool hasDirectFields() const {
+    auto &D = data();
+    return D.HasPublicFields || D.HasProtectedFields || D.HasPrivateFields;
+  }
+
   /// Whether this class is polymorphic (C++ [class.virtual]),
   /// which means that the class contains or inherits a virtual function.
   bool isPolymorphic() const { return data().Polymorphic; }
@@ -3451,6 +3457,8 @@ public:
     return llvm::makeArrayRef(getTrailingObjects<BindingDecl *>(), NumBindings);
   }
 
+  void printName(raw_ostream &os) const override;
+
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classofKind(Kind K) { return K == Decomposition; }
 

Modified: cfe/trunk/include/clang/AST/UnresolvedSet.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/UnresolvedSet.h?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/UnresolvedSet.h (original)
+++ cfe/trunk/include/clang/AST/UnresolvedSet.h Thu Aug 11 17:25:46 2016
@@ -38,7 +38,7 @@ class UnresolvedSetIterator : public llv
       : iterator_adaptor_base(const_cast<DeclAccessPair *>(Iter)) {}
 
 public:
-  UnresolvedSetIterator() {}
+  UnresolvedSetIterator() = default;
 
   NamedDecl *getDecl() const { return I->getDecl(); }
   void setDecl(NamedDecl *ND) const { return I->setDecl(ND); }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug 11 17:25:46 2016
@@ -385,6 +385,40 @@ def err_decomp_decl_template : Error<
   "decomposition declaration template not supported">;
 def err_decomp_decl_not_alone : Error<
   "decomposition declaration must be the only declaration in its group">;
+def err_decomp_decl_requires_init : Error<
+  "decomposition declaration %0 requires an initializer">;
+def err_decomp_decl_paren_init : Error<
+  "decomposition declaration %0 cannot have a parenthesized initializer">;
+def err_decomp_decl_wrong_number_bindings : Error<
+  "type %0 decomposes into %2 elements, but %select{only |}3%1 "
+  "names were provided">;
+def err_decomp_decl_unbindable_type : Error<
+  "cannot decompose %select{union|non-class, non-array}1 type %2">;
+def err_decomp_decl_multiple_bases_with_members : Error<
+  "cannot decompose class type %1: "
+  "%select{its base classes %2 and|both it and its base class}0 %3 "
+  "have non-static data members">;
+def err_decomp_decl_ambiguous_base : Error<
+  "cannot decompose members of ambiguous base class %1 of %0:%2">;
+def err_decomp_decl_non_public_base : Error<
+  "cannot decompose members of non-public base class %1 of %0">;
+def err_decomp_decl_non_public_member : Error<
+  "cannot decompose non-public member %0 of %1">;
+def err_decomp_decl_anon_union_member : Error<
+  "cannot decompose class type %1 because it has an anonymous "
+  "%select{struct|union} member">;
+def err_decomp_decl_std_tuple_element_not_specialized : Error<
+  "cannot decompose this type; 'std::tuple_element<%0>::type' "
+  "does not name a type">;
+def err_decomp_decl_std_tuple_size_not_constant : Error<
+  "cannot decompose this type; 'std::tuple_size<%0>::value' "
+  "is not a valid integral constant expression">;
+def note_in_binding_decl_init : Note<
+  "in implicit initialization of binding declaration %0">;
+
+def err_std_type_trait_not_class_template : Error<
+  "unsupported standard library implementation: "
+  "'std::%0' is not a class template">;
 
 // C++ using declarations
 def err_using_requires_qualname : Error<

Modified: cfe/trunk/include/clang/Sema/Initialization.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Initialization.h?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Initialization.h (original)
+++ cfe/trunk/include/clang/Sema/Initialization.h Thu Aug 11 17:25:46 2016
@@ -84,7 +84,10 @@ public:
     EK_RelatedResult,
     /// \brief The entity being initialized is a function parameter; function
     /// is member of group of audited CF APIs.
-    EK_Parameter_CF_Audited
+    EK_Parameter_CF_Audited,
+    /// \brief The entity being initialized is a structured binding of a
+    /// decomposition declaration.
+    EK_Binding,
 
     // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses this
     // enum as an index for its first %select.  When modifying this list,
@@ -126,9 +129,9 @@ private:
   };
 
   union {
-    /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or
-    /// FieldDecl, respectively.
-    DeclaratorDecl *VariableOrMember;
+    /// \brief When Kind == EK_Variable, EK_Member or EK_Binding, the VarDecl,
+    /// FieldDecl or BindingDecl, respectively.
+    ValueDecl *VariableOrMember;
     
     /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where
     /// result type was implicitly changed to accommodate ARC semantics.
@@ -180,6 +183,12 @@ private:
     : Kind(EK_Member), Parent(Parent), Type(Member->getType()),
       ManglingNumber(0), VariableOrMember(Member) { }
   
+  /// \brief Create the initialization entity for a binding.
+  InitializedEntity(BindingDecl *Binding, QualType Type,
+                    const InitializedEntity &Parent)
+    : Kind(EK_Binding), Parent(&Parent), Type(Type),
+      ManglingNumber(0), VariableOrMember(Binding) {}
+
   /// \brief Create the initialization entity for an array element.
   InitializedEntity(ASTContext &Context, unsigned Index, 
                     const InitializedEntity &Parent);
@@ -314,6 +323,13 @@ public:
     return InitializedEntity(Context, Index, Parent);
   }
 
+  /// \brief Create the initialization entity for a structured binding.
+  static InitializedEntity InitializeBinding(const InitializedEntity &Parent,
+                                             BindingDecl *Binding,
+                                             QualType Type) {
+    return InitializedEntity(Binding, Type, Parent);
+  }
+
   /// \brief Create the initialization entity for a lambda capture.
   static InitializedEntity InitializeLambdaCapture(IdentifierInfo *VarID,
                                                    QualType FieldType,
@@ -355,7 +371,7 @@ public:
 
   /// \brief Retrieve the variable, parameter, or field being
   /// initialized.
-  DeclaratorDecl *getDecl() const;
+  ValueDecl *getDecl() const;
   
   /// \brief Retrieve the ObjectiveC method being initialized.
   ObjCMethodDecl *getMethodDecl() const { return MethodDecl; }

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Aug 11 17:25:46 2016
@@ -1728,7 +1728,9 @@ public:
   // Returns true if the variable declaration is a redeclaration
   bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
   void CheckVariableDeclarationType(VarDecl *NewVD);
-  void CheckCompleteVariableDeclaration(VarDecl *var);
+  void CheckCompleteVariableDeclaration(VarDecl *VD, InitializedEntity &Entity);
+  void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD,
+                                             InitializedEntity &Entity);
   void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
 
   NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
@@ -3970,6 +3972,12 @@ public:
                            bool SuppressQualifierCheck = false,
                            ActOnMemberAccessExtraArgs *ExtraArgs = nullptr);
 
+  ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
+                                     SourceLocation OpLoc,
+                                     const CXXScopeSpec &SS, FieldDecl *Field,
+                                     DeclAccessPair FoundDecl,
+                                     const DeclarationNameInfo &MemberNameInfo);
+
   ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow);
 
   bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType,
@@ -5772,6 +5780,10 @@ public:
                             TemplateParameterList **OuterTemplateParamLists,
                                 SkipBodyInfo *SkipBody = nullptr);
 
+  TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
+                                                    QualType NTTPType,
+                                                    SourceLocation Loc);
+
   void translateTemplateArguments(const ASTTemplateArgsPtr &In,
                                   TemplateArgumentListInfo &Out);
 

Modified: cfe/trunk/lib/AST/ASTDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDumper.cpp (original)
+++ cfe/trunk/lib/AST/ASTDumper.cpp Thu Aug 11 17:25:46 2016
@@ -429,6 +429,7 @@ namespace  {
     void VisitFieldDecl(const FieldDecl *D);
     void VisitVarDecl(const VarDecl *D);
     void VisitDecompositionDecl(const DecompositionDecl *D);
+    void VisitBindingDecl(const BindingDecl *D);
     void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);
     void VisitImportDecl(const ImportDecl *D);
     void VisitPragmaCommentDecl(const PragmaCommentDecl *D);
@@ -1224,6 +1225,13 @@ void ASTDumper::VisitDecompositionDecl(c
     dumpDecl(B);
 }
 
+void ASTDumper::VisitBindingDecl(const BindingDecl *D) {
+  dumpName(D);
+  dumpType(D->getType());
+  if (auto *E = D->getBinding())
+    dumpStmt(E);
+}
+
 void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
   dumpStmt(D->getAsmString());
 }

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Aug 11 17:25:46 2016
@@ -1395,6 +1395,10 @@ static LinkageInfo getLVForDecl(const Na
   return clang::LinkageComputer::getLVForDecl(D, computation);
 }
 
+void NamedDecl::printName(raw_ostream &os) const {
+  os << Name;
+}
+
 std::string NamedDecl::getQualifiedNameAsString() const {
   std::string QualName;
   llvm::raw_string_ostream OS(QualName);
@@ -1481,7 +1485,7 @@ void NamedDecl::printQualifiedName(raw_o
     OS << "::";
   }
 
-  if (getDeclName())
+  if (getDeclName() || isa<DecompositionDecl>(this))
     OS << *this;
   else
     OS << "(anonymous)";

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Aug 11 17:25:46 2016
@@ -2344,6 +2344,18 @@ DecompositionDecl *DecompositionDecl::Cr
   return Result;
 }
 
+void DecompositionDecl::printName(llvm::raw_ostream &os) const {
+  os << '[';
+  bool Comma = false;
+  for (auto *B : bindings()) {
+    if (Comma)
+      os << ", ";
+    B->printName(os);
+    Comma = true;
+  }
+  os << ']';
+}
+
 MSPropertyDecl *MSPropertyDecl::Create(ASTContext &C, DeclContext *DC,
                                        SourceLocation L, DeclarationName N,
                                        QualType T, TypeSourceInfo *TInfo,

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Thu Aug 11 17:25:46 2016
@@ -3308,11 +3308,16 @@ FieldDecl *Expr::getSourceBitField() {
       if (Ivar->isBitField())
         return Ivar;
 
-  if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E))
+  if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) {
     if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl()))
       if (Field->isBitField())
         return Field;
 
+    if (BindingDecl *BD = dyn_cast<BindingDecl>(DeclRef->getDecl()))
+      if (Expr *E = BD->getBinding())
+        return E->getSourceBitField();
+  }
+
   if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) {
     if (BinOp->isAssignmentOp() && BinOp->getLHS())
       return BinOp->getLHS()->getSourceBitField();
@@ -3329,6 +3334,7 @@ FieldDecl *Expr::getSourceBitField() {
 }
 
 bool Expr::refersToVectorElement() const {
+  // FIXME: Why do we not just look at the ObjectKind here?
   const Expr *E = this->IgnoreParens();
   
   while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
@@ -3345,6 +3351,11 @@ bool Expr::refersToVectorElement() const
   if (isa<ExtVectorElementExpr>(E))
     return true;
 
+  if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+    if (auto *BD = dyn_cast<BindingDecl>(DRE->getDecl()))
+      if (auto *E = BD->getBinding())
+        return E->refersToVectorElement();
+
   return false;
 }
 

Modified: cfe/trunk/lib/AST/ExprClassification.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprClassification.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprClassification.cpp (original)
+++ cfe/trunk/lib/AST/ExprClassification.cpp Thu Aug 11 17:25:46 2016
@@ -429,6 +429,7 @@ static Cl::Kinds ClassifyDecl(ASTContext
   else
     islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
                isa<IndirectFieldDecl>(D) ||
+               isa<BindingDecl>(D) ||
                (Ctx.getLangOpts().CPlusPlus &&
                 (isa<FunctionDecl>(D) || isa<MSPropertyDecl>(D) ||
                  isa<FunctionTemplateDecl>(D)));

Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Thu Aug 11 17:25:46 2016
@@ -28,6 +28,7 @@
 #include "clang/Sema/CXXFieldCollector.h"
 #include "clang/Sema/DelayedDiagnostic.h"
 #include "clang/Sema/ExternalSemaSource.h"
+#include "clang/Sema/Initialization.h"
 #include "clang/Sema/MultiplexExternalSemaSource.h"
 #include "clang/Sema/ObjCMethodList.h"
 #include "clang/Sema/PrettyDeclStackTrace.h"
@@ -809,7 +810,9 @@ void Sema::ActOnEndOfTranslationUnit() {
                                    diag::err_tentative_def_incomplete_type))
       VD->setInvalidDecl();
 
-    CheckCompleteVariableDeclaration(VD);
+    // No initialization is performed for a tentative definition.
+    InitializedEntity Entity = InitializedEntity::InitializeVariable(VD);
+    CheckCompleteVariableDeclaration(VD, Entity);
 
     // Notify the consumer that we've completed a tentative definition.
     if (!VD->isInvalidDecl())

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Aug 11 17:25:46 2016
@@ -43,7 +43,6 @@
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Triple.h"
 #include <algorithm>
 #include <cstring>
@@ -6534,157 +6533,6 @@ NamedDecl *Sema::ActOnVariableDeclarator
   return NewVD;
 }
 
-NamedDecl *
-Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
-                                   MultiTemplateParamsArg TemplateParamLists) {
-  assert(D.isDecompositionDeclarator());
-  const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator();
-
-  // The syntax only allows a decomposition declarator as a simple-declaration
-  // or a for-range-declaration, but we parse it in more cases than that.
-  if (!D.mayHaveDecompositionDeclarator()) {
-    Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)
-      << Decomp.getSourceRange();
-    return nullptr;
-  }
-
-  if (!TemplateParamLists.empty()) {
-    // FIXME: There's no rule against this, but there are also no rules that
-    // would actually make it usable, so we reject it for now.
-    Diag(TemplateParamLists.front()->getTemplateLoc(),
-         diag::err_decomp_decl_template);
-    return nullptr;
-  }
-
-  Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z
-                                   ? diag::warn_cxx14_compat_decomp_decl
-                                   : diag::ext_decomp_decl)
-      << Decomp.getSourceRange();
-
-  // The semantic context is always just the current context.
-  DeclContext *const DC = CurContext;
-
-  // C++1z [dcl.dcl]/8:
-  //   The decl-specifier-seq shall contain only the type-specifier auto
-  //   and cv-qualifiers.
-  auto &DS = D.getDeclSpec();
-  {
-    SmallVector<StringRef, 8> BadSpecifiers;
-    SmallVector<SourceLocation, 8> BadSpecifierLocs;
-    if (auto SCS = DS.getStorageClassSpec()) {
-      BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS));
-      BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc());
-    }
-    if (auto TSCS = DS.getThreadStorageClassSpec()) {
-      BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS));
-      BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
-    }
-    if (DS.isConstexprSpecified()) {
-      BadSpecifiers.push_back("constexpr");
-      BadSpecifierLocs.push_back(DS.getConstexprSpecLoc());
-    }
-    if (DS.isInlineSpecified()) {
-      BadSpecifiers.push_back("inline");
-      BadSpecifierLocs.push_back(DS.getInlineSpecLoc());
-    }
-    if (!BadSpecifiers.empty()) {
-      auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);
-      Err << (int)BadSpecifiers.size()
-          << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " ");
-      // Don't add FixItHints to remove the specifiers; we do still respect
-      // them when building the underlying variable.
-      for (auto Loc : BadSpecifierLocs)
-        Err << SourceRange(Loc, Loc);
-    }
-    // We can't recover from it being declared as a typedef.
-    if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
-      return nullptr;
-  }
-
-  TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
-  QualType R = TInfo->getType();
-
-  if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
-                                      UPPC_DeclarationType))
-    D.setInvalidType();
-
-  // The syntax only allows a single ref-qualifier prior to the decomposition
-  // declarator. No other declarator chunks are permitted. Also check the type
-  // specifier here.
-  if (DS.getTypeSpecType() != DeclSpec::TST_auto ||
-      D.hasGroupingParens() || D.getNumTypeObjects() > 1 ||
-      (D.getNumTypeObjects() == 1 &&
-       D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) {
-    Diag(Decomp.getLSquareLoc(),
-         (D.hasGroupingParens() ||
-          (D.getNumTypeObjects() &&
-           D.getTypeObject(0).Kind == DeclaratorChunk::Paren))
-             ? diag::err_decomp_decl_parens
-             : diag::err_decomp_decl_type)
-        << R;
-
-    // In most cases, there's no actual problem with an explicitly-specified
-    // type, but a function type won't work here, and ActOnVariableDeclarator
-    // shouldn't be called for such a type.
-    if (R->isFunctionType())
-      D.setInvalidType();
-  }
-
-  // Build the BindingDecls.
-  SmallVector<BindingDecl*, 8> Bindings;
-
-  // Build the BindingDecls.
-  for (auto &B : D.getDecompositionDeclarator().bindings()) {
-    // Check for name conflicts.
-    DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
-    LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
-                          ForRedeclaration);
-    LookupName(Previous, S,
-               /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit());
-
-    // It's not permitted to shadow a template parameter name.
-    if (Previous.isSingleResult() &&
-        Previous.getFoundDecl()->isTemplateParameter()) {
-      DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
-                                      Previous.getFoundDecl());
-      Previous.clear();
-    }
-
-    bool ConsiderLinkage = DC->isFunctionOrMethod() &&
-                           DS.getStorageClassSpec() == DeclSpec::SCS_extern;
-    FilterLookupForScope(Previous, DC, S, ConsiderLinkage,
-                         /*AllowInlineNamespace*/false);
-    if (!Previous.empty()) {
-      auto *Old = Previous.getRepresentativeDecl();
-      Diag(B.NameLoc, diag::err_redefinition) << B.Name;
-      Diag(Old->getLocation(), diag::note_previous_definition);
-    }
-
-    auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);
-    PushOnScopeChains(BD, S, true);
-    Bindings.push_back(BD);
-    ParsingInitForAutoVars.insert(BD);
-  }
-
-  // There are no prior lookup results for the variable itself, because it
-  // is unnamed.
-  DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,
-                               Decomp.getLSquareLoc());
-  LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
-
-  // Build the variable that holds the non-decomposed object.
-  bool AddToScope = true;
-  NamedDecl *New =
-      ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
-                              MultiTemplateParamsArg(), AddToScope, Bindings);
-  CurContext->addHiddenDecl(New);
-
-  if (isInOpenMPDeclareTargetContext())
-    checkDeclIsAllowedInOpenMPTarget(nullptr, New);
-
-  return New;
-}
-
 /// Enum describing the %select options in diag::warn_decl_shadow.
 enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field };
 
@@ -9604,6 +9452,9 @@ QualType Sema::deduceVarTypeFromInitiali
   assert((!VDecl || !VDecl->isInitCapture()) &&
          "init captures are expected to be deduced prior to initialization");
 
+  // FIXME: Deduction for a decomposition declaration does weird things if the
+  // initializer is an array.
+
   ArrayRef<Expr *> DeduceInits = Init;
   if (DirectInit) {
     if (auto *PL = dyn_cast<ParenListExpr>(Init))
@@ -9713,6 +9564,11 @@ void Sema::AddInitializerToDecl(Decl *Re
     return;
   }
 
+  // C++1z [dcl.dcl]p1 grammar implies that a parenthesized initializer is not
+  // permitted.
+  if (isa<DecompositionDecl>(VDecl) && DirectInit && isa<ParenListExpr>(Init))
+    Diag(VDecl->getLocation(), diag::err_decomp_decl_paren_init) << VDecl;
+
   // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
   if (TypeMayContainAuto && VDecl->getType()->isUndeducedType()) {
     // Attempt typo correction early so that the type of the init expression can
@@ -9864,8 +9720,8 @@ void Sema::AddInitializerToDecl(Decl *Re
 
   // Perform the initialization.
   ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init);
+  InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
   if (!VDecl->isInvalidDecl()) {
-    InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
     InitializationKind Kind =
         DirectInit
             ? CXXDirectInit
@@ -10116,7 +9972,7 @@ void Sema::AddInitializerToDecl(Decl *Re
     VDecl->setInitStyle(VarDecl::ListInit);
   }
 
-  CheckCompleteVariableDeclaration(VDecl);
+  CheckCompleteVariableDeclaration(VDecl, Entity);
 }
 
 /// ActOnInitializerError - Given that there was an error parsing an
@@ -10173,6 +10029,13 @@ void Sema::ActOnUninitializedDecl(Decl *
   if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
     QualType Type = Var->getType();
 
+    // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory.
+    if (isa<DecompositionDecl>(RealDecl)) {
+      Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var;
+      Var->setInvalidDecl();
+      return;
+    }
+
     // C++11 [dcl.spec.auto]p3
     if (TypeMayContainAuto && Type->getContainedAutoType()) {
       Diag(Var->getLocation(), diag::err_auto_var_requires_init)
@@ -10394,7 +10257,7 @@ void Sema::ActOnUninitializedDecl(Decl *
       Var->setInitStyle(VarDecl::CallInit);
     }
 
-    CheckCompleteVariableDeclaration(Var);
+    CheckCompleteVariableDeclaration(Var, Entity);
   }
 }
 
@@ -10471,7 +10334,8 @@ Sema::ActOnCXXForRangeIdentifier(Scope *
                        AttrEnd.isValid() ? AttrEnd : IdentLoc);
 }
 
-void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
+void Sema::CheckCompleteVariableDeclaration(VarDecl *var,
+                                            InitializedEntity &Entity) {
   if (var->isInvalidDecl()) return;
 
   if (getLangOpts().OpenCL) {
@@ -10580,6 +10444,9 @@ void Sema::CheckCompleteVariableDeclarat
   // All the following checks are C++ only.
   if (!getLangOpts().CPlusPlus) return;
 
+  if (auto *DD = dyn_cast<DecompositionDecl>(var))
+    CheckCompleteDecompositionDeclaration(DD, Entity);
+
   QualType type = var->getType();
   if (type->isDependentType()) return;
 
@@ -10680,9 +10547,13 @@ Sema::FinalizeDeclaration(Decl *ThisDecl
   if (!VD)
     return;
 
-  if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl))
-    for (auto *BD : DD->bindings())
+  if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) {
+    for (auto *BD : DD->bindings()) {
+      if (ThisDecl->isInvalidDecl())
+        BD->setInvalidDecl();
       FinalizeDeclaration(BD);
+    }
+  }
 
   checkAttributesAfterMerging(*this, *VD);
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Aug 11 17:25:46 2016
@@ -39,6 +39,7 @@
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include <map>
 #include <set>
 
@@ -664,6 +665,753 @@ bool Sema::MergeCXXFunctionDecl(Function
   return Invalid;
 }
 
+NamedDecl *
+Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D,
+                                   MultiTemplateParamsArg TemplateParamLists) {
+  assert(D.isDecompositionDeclarator());
+  const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator();
+
+  // The syntax only allows a decomposition declarator as a simple-declaration
+  // or a for-range-declaration, but we parse it in more cases than that.
+  if (!D.mayHaveDecompositionDeclarator()) {
+    Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context)
+      << Decomp.getSourceRange();
+    return nullptr;
+  }
+
+  if (!TemplateParamLists.empty()) {
+    // FIXME: There's no rule against this, but there are also no rules that
+    // would actually make it usable, so we reject it for now.
+    Diag(TemplateParamLists.front()->getTemplateLoc(),
+         diag::err_decomp_decl_template);
+    return nullptr;
+  }
+
+  Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z
+                                   ? diag::warn_cxx14_compat_decomp_decl
+                                   : diag::ext_decomp_decl)
+      << Decomp.getSourceRange();
+
+  // The semantic context is always just the current context.
+  DeclContext *const DC = CurContext;
+
+  // C++1z [dcl.dcl]/8:
+  //   The decl-specifier-seq shall contain only the type-specifier auto
+  //   and cv-qualifiers.
+  auto &DS = D.getDeclSpec();
+  {
+    SmallVector<StringRef, 8> BadSpecifiers;
+    SmallVector<SourceLocation, 8> BadSpecifierLocs;
+    if (auto SCS = DS.getStorageClassSpec()) {
+      BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS));
+      BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc());
+    }
+    if (auto TSCS = DS.getThreadStorageClassSpec()) {
+      BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS));
+      BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc());
+    }
+    if (DS.isConstexprSpecified()) {
+      BadSpecifiers.push_back("constexpr");
+      BadSpecifierLocs.push_back(DS.getConstexprSpecLoc());
+    }
+    if (DS.isInlineSpecified()) {
+      BadSpecifiers.push_back("inline");
+      BadSpecifierLocs.push_back(DS.getInlineSpecLoc());
+    }
+    if (!BadSpecifiers.empty()) {
+      auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec);
+      Err << (int)BadSpecifiers.size()
+          << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " ");
+      // Don't add FixItHints to remove the specifiers; we do still respect
+      // them when building the underlying variable.
+      for (auto Loc : BadSpecifierLocs)
+        Err << SourceRange(Loc, Loc);
+    }
+    // We can't recover from it being declared as a typedef.
+    if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef)
+      return nullptr;
+  }
+
+  TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
+  QualType R = TInfo->getType();
+
+  if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo,
+                                      UPPC_DeclarationType))
+    D.setInvalidType();
+
+  // The syntax only allows a single ref-qualifier prior to the decomposition
+  // declarator. No other declarator chunks are permitted. Also check the type
+  // specifier here.
+  if (DS.getTypeSpecType() != DeclSpec::TST_auto ||
+      D.hasGroupingParens() || D.getNumTypeObjects() > 1 ||
+      (D.getNumTypeObjects() == 1 &&
+       D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) {
+    Diag(Decomp.getLSquareLoc(),
+         (D.hasGroupingParens() ||
+          (D.getNumTypeObjects() &&
+           D.getTypeObject(0).Kind == DeclaratorChunk::Paren))
+             ? diag::err_decomp_decl_parens
+             : diag::err_decomp_decl_type)
+        << R;
+
+    // In most cases, there's no actual problem with an explicitly-specified
+    // type, but a function type won't work here, and ActOnVariableDeclarator
+    // shouldn't be called for such a type.
+    if (R->isFunctionType())
+      D.setInvalidType();
+  }
+
+  // Build the BindingDecls.
+  SmallVector<BindingDecl*, 8> Bindings;
+
+  // Build the BindingDecls.
+  for (auto &B : D.getDecompositionDeclarator().bindings()) {
+    // Check for name conflicts.
+    DeclarationNameInfo NameInfo(B.Name, B.NameLoc);
+    LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
+                          ForRedeclaration);
+    LookupName(Previous, S,
+               /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit());
+
+    // It's not permitted to shadow a template parameter name.
+    if (Previous.isSingleResult() &&
+        Previous.getFoundDecl()->isTemplateParameter()) {
+      DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
+                                      Previous.getFoundDecl());
+      Previous.clear();
+    }
+
+    bool ConsiderLinkage = DC->isFunctionOrMethod() &&
+                           DS.getStorageClassSpec() == DeclSpec::SCS_extern;
+    FilterLookupForScope(Previous, DC, S, ConsiderLinkage,
+                         /*AllowInlineNamespace*/false);
+    if (!Previous.empty()) {
+      auto *Old = Previous.getRepresentativeDecl();
+      Diag(B.NameLoc, diag::err_redefinition) << B.Name;
+      Diag(Old->getLocation(), diag::note_previous_definition);
+    }
+
+    auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name);
+    PushOnScopeChains(BD, S, true);
+    Bindings.push_back(BD);
+    ParsingInitForAutoVars.insert(BD);
+  }
+
+  // There are no prior lookup results for the variable itself, because it
+  // is unnamed.
+  DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr,
+                               Decomp.getLSquareLoc());
+  LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration);
+
+  // Build the variable that holds the non-decomposed object.
+  bool AddToScope = true;
+  NamedDecl *New =
+      ActOnVariableDeclarator(S, D, DC, TInfo, Previous,
+                              MultiTemplateParamsArg(), AddToScope, Bindings);
+  CurContext->addHiddenDecl(New);
+
+  if (isInOpenMPDeclareTargetContext())
+    checkDeclIsAllowedInOpenMPTarget(nullptr, New);
+
+  return New;
+}
+
+static bool checkSimpleDecomposition(
+    Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src,
+    QualType DecompType, llvm::APSInt NumElems, QualType ElemType,
+    llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) {
+  if ((int64_t)Bindings.size() != NumElems) {
+    S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
+        << DecompType << (unsigned)Bindings.size() << NumElems.toString(10)
+        << (NumElems < Bindings.size());
+    return true;
+  }
+
+  unsigned I = 0;
+  for (auto *B : Bindings) {
+    SourceLocation Loc = B->getLocation();
+    ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
+    if (E.isInvalid())
+      return true;
+    E = GetInit(Loc, E.get(), I++);
+    if (E.isInvalid())
+      return true;
+    B->setBinding(ElemType, E.get());
+  }
+
+  return false;
+}
+
+static bool checkArrayLikeDecomposition(Sema &S,
+                                        ArrayRef<BindingDecl *> Bindings,
+                                        ValueDecl *Src, QualType DecompType,
+                                        llvm::APSInt NumElems,
+                                        QualType ElemType) {
+  return checkSimpleDecomposition(
+      S, Bindings, Src, DecompType, NumElems, ElemType,
+      [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult {
+        ExprResult E = S.ActOnIntegerConstant(Loc, I);
+        if (E.isInvalid())
+          return ExprError();
+        return S.CreateBuiltinArraySubscriptExpr(Base, Loc, E.get(), Loc);
+      });
+}
+
+static bool checkArrayDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
+                                    ValueDecl *Src, QualType DecompType,
+                                    const ConstantArrayType *CAT) {
+  return checkArrayLikeDecomposition(S, Bindings, Src, DecompType,
+                                     llvm::APSInt(CAT->getSize()),
+                                     CAT->getElementType());
+}
+
+static bool checkVectorDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
+                                     ValueDecl *Src, QualType DecompType,
+                                     const VectorType *VT) {
+  return checkArrayLikeDecomposition(
+      S, Bindings, Src, DecompType, llvm::APSInt::get(VT->getNumElements()),
+      S.Context.getQualifiedType(VT->getElementType(),
+                                 DecompType.getQualifiers()));
+}
+
+static bool checkComplexDecomposition(Sema &S,
+                                      ArrayRef<BindingDecl *> Bindings,
+                                      ValueDecl *Src, QualType DecompType,
+                                      const ComplexType *CT) {
+  return checkSimpleDecomposition(
+      S, Bindings, Src, DecompType, llvm::APSInt::get(2),
+      S.Context.getQualifiedType(CT->getElementType(),
+                                 DecompType.getQualifiers()),
+      [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult {
+        return S.CreateBuiltinUnaryOp(Loc, I ? UO_Imag : UO_Real, Base);
+      });
+}
+
+static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy,
+                                     TemplateArgumentListInfo &Args) {
+  SmallString<128> SS;
+  llvm::raw_svector_ostream OS(SS);
+  bool First = true;
+  for (auto &Arg : Args.arguments()) {
+    if (!First)
+      OS << ", ";
+    Arg.getArgument().print(PrintingPolicy, OS);
+    First = false;
+  }
+  return OS.str();
+}
+
+static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup,
+                                     SourceLocation Loc, StringRef Trait,
+                                     TemplateArgumentListInfo &Args,
+                                     unsigned DiagID) {
+  auto DiagnoseMissing = [&] {
+    if (DiagID)
+      S.Diag(Loc, DiagID) << printTemplateArgs(S.Context.getPrintingPolicy(),
+                                               Args);
+    return true;
+  };
+
+  // FIXME: Factor out duplication with lookupPromiseType in SemaCoroutine.
+  NamespaceDecl *Std = S.getStdNamespace();
+  if (!Std)
+    return DiagnoseMissing();
+
+  // Look up the trait itself, within namespace std. We can diagnose various
+  // problems with this lookup even if we've been asked to not diagnose a
+  // missing specialization, because this can only fail if the user has been
+  // declaring their own names in namespace std or we don't support the
+  // standard library implementation in use.
+  LookupResult Result(S, &S.PP.getIdentifierTable().get(Trait),
+                      Loc, Sema::LookupOrdinaryName);
+  if (!S.LookupQualifiedName(Result, Std))
+    return DiagnoseMissing();
+  if (Result.isAmbiguous())
+    return true;
+
+  ClassTemplateDecl *TraitTD = Result.getAsSingle<ClassTemplateDecl>();
+  if (!TraitTD) {
+    Result.suppressDiagnostics();
+    NamedDecl *Found = *Result.begin();
+    S.Diag(Loc, diag::err_std_type_trait_not_class_template) << Trait;
+    S.Diag(Found->getLocation(), diag::note_declared_at);
+    return true;
+  }
+
+  // Build the template-id.
+  QualType TraitTy = S.CheckTemplateIdType(TemplateName(TraitTD), Loc, Args);
+  if (TraitTy.isNull())
+    return true;
+  if (!S.isCompleteType(Loc, TraitTy)) {
+    if (DiagID)
+      S.RequireCompleteType(
+          Loc, TraitTy, DiagID,
+          printTemplateArgs(S.Context.getPrintingPolicy(), Args));
+    return true;
+  }
+
+  CXXRecordDecl *RD = TraitTy->getAsCXXRecordDecl();
+  assert(RD && "specialization of class template is not a class?");
+
+  // Look up the member of the trait type.
+  S.LookupQualifiedName(TraitMemberLookup, RD);
+  return TraitMemberLookup.isAmbiguous();
+}
+
+static TemplateArgumentLoc
+getTrivialIntegralTemplateArgument(Sema &S, SourceLocation Loc, QualType T,
+                                   uint64_t I) {
+  TemplateArgument Arg(S.Context, S.Context.MakeIntValue(I, T), T);
+  return S.getTrivialTemplateArgumentLoc(Arg, T, Loc);
+}
+
+static TemplateArgumentLoc
+getTrivialTypeTemplateArgument(Sema &S, SourceLocation Loc, QualType T) {
+  return S.getTrivialTemplateArgumentLoc(TemplateArgument(T), QualType(), Loc);
+}
+
+namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; }
+
+static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T,
+                               llvm::APSInt &Size) {
+  EnterExpressionEvaluationContext ContextRAII(S, Sema::ConstantEvaluated);
+
+  DeclarationName Value = S.PP.getIdentifierInfo("value");
+  LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName);
+
+  // Form template argument list for tuple_size<T>.
+  TemplateArgumentListInfo Args(Loc, Loc);
+  Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T));
+
+  // If there's no tuple_size specialization, it's not tuple-like.
+  if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0))
+    return IsTupleLike::NotTupleLike;
+
+  // FIXME: According to the standard, we're not supposed to diagnose if any
+  // of the steps below fail (or if lookup for ::value is ambiguous or otherwise
+  // results in an error), but this is subject to a pending CWG issue / NB
+  // comment, which says we do diagnose if tuple_size<T> is complete but
+  // tuple_size<T>::value is not an ICE.
+
+  struct ICEDiagnoser : Sema::VerifyICEDiagnoser {
+    LookupResult &R;
+    TemplateArgumentListInfo &Args;
+    ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args)
+        : R(R), Args(Args) {}
+    void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) {
+      S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant)
+          << printTemplateArgs(S.Context.getPrintingPolicy(), Args);
+    }
+  } Diagnoser(R, Args);
+
+  if (R.empty()) {
+    Diagnoser.diagnoseNotICE(S, Loc, SourceRange());
+    return IsTupleLike::Error;
+  }
+
+  ExprResult E =
+      S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false);
+  if (E.isInvalid())
+    return IsTupleLike::Error;
+
+  E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser, false);
+  if (E.isInvalid())
+    return IsTupleLike::Error;
+
+  return IsTupleLike::TupleLike;
+}
+
+/// \return std::tuple_element<I, T>::type.
+static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc,
+                                        unsigned I, QualType T) {
+  // Form template argument list for tuple_element<I, T>.
+  TemplateArgumentListInfo Args(Loc, Loc);
+  Args.addArgument(
+      getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I));
+  Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T));
+
+  DeclarationName TypeDN = S.PP.getIdentifierInfo("type");
+  LookupResult R(S, TypeDN, Loc, Sema::LookupOrdinaryName);
+  if (lookupStdTypeTraitMember(
+          S, R, Loc, "tuple_element", Args,
+          diag::err_decomp_decl_std_tuple_element_not_specialized))
+    return QualType();
+
+  auto *TD = R.getAsSingle<TypeDecl>();
+  if (!TD) {
+    R.suppressDiagnostics();
+    S.Diag(Loc, diag::err_decomp_decl_std_tuple_element_not_specialized)
+      << printTemplateArgs(S.Context.getPrintingPolicy(), Args);
+    if (!R.empty())
+      S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at);
+    return QualType();
+  }
+
+  return S.Context.getTypeDeclType(TD);
+}
+
+namespace {
+struct BindingDiagnosticTrap {
+  Sema &S;
+  DiagnosticErrorTrap Trap;
+  BindingDecl *BD;
+
+  BindingDiagnosticTrap(Sema &S, BindingDecl *BD)
+      : S(S), Trap(S.Diags), BD(BD) {}
+  ~BindingDiagnosticTrap() {
+    if (Trap.hasErrorOccurred())
+      S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD;
+  }
+};
+}
+
+static bool
+checkTupleLikeDecomposition(Sema &S, ArrayRef<BindingDecl *> Bindings,
+                            ValueDecl *Src, InitializedEntity &ParentEntity,
+                            QualType DecompType, llvm::APSInt TupleSize) {
+  if ((int64_t)Bindings.size() != TupleSize) {
+    S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
+        << DecompType << (unsigned)Bindings.size() << TupleSize.toString(10)
+        << (TupleSize < Bindings.size());
+    return true;
+  }
+
+  if (Bindings.empty())
+    return false;
+
+  DeclarationName GetDN = S.PP.getIdentifierInfo("get");
+
+  // [dcl.decomp]p3:
+  //   The unqualified-id get is looked up in the scope of E by class member
+  //   access lookup
+  LookupResult MemberGet(S, GetDN, Src->getLocation(), Sema::LookupMemberName);
+  bool UseMemberGet = false;
+  if (S.isCompleteType(Src->getLocation(), DecompType)) {
+    if (auto *RD = DecompType->getAsCXXRecordDecl())
+      S.LookupQualifiedName(MemberGet, RD);
+    if (MemberGet.isAmbiguous())
+      return true;
+    UseMemberGet = !MemberGet.empty();
+    S.FilterAcceptableTemplateNames(MemberGet);
+  }
+
+  unsigned I = 0;
+  for (auto *B : Bindings) {
+    BindingDiagnosticTrap Trap(S, B);
+    SourceLocation Loc = B->getLocation();
+
+    ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
+    if (E.isInvalid())
+      return true;
+
+    //   e is an lvalue if the type of the entity is an lvalue reference and
+    //   an xvalue otherwise
+    if (!Src->getType()->isLValueReferenceType())
+      E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), CK_NoOp,
+                                   E.get(), nullptr, VK_XValue);
+
+    TemplateArgumentListInfo Args(Loc, Loc);
+    Args.addArgument(
+        getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I));
+
+    if (UseMemberGet) {
+      //   if [lookup of member get] finds at least one declaration, the
+      //   initializer is e.get<i-1>().
+      E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, false,
+                                     CXXScopeSpec(), SourceLocation(), nullptr,
+                                     MemberGet, &Args, nullptr);
+      if (E.isInvalid())
+        return true;
+
+      E = S.ActOnCallExpr(nullptr, E.get(), Loc, None, Loc);
+    } else {
+      //   Otherwise, the initializer is get<i-1>(e), where get is looked up
+      //   in the associated namespaces.
+      Expr *Get = UnresolvedLookupExpr::Create(
+          S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
+          DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/true, &Args,
+          UnresolvedSetIterator(), UnresolvedSetIterator());
+
+      Expr *Arg = E.get();
+      E = S.ActOnCallExpr(nullptr, Get, Loc, Arg, Loc);
+    }
+    if (E.isInvalid())
+      return true;
+    Expr *Init = E.get();
+
+    //   Given the type T designated by std::tuple_element<i - 1, E>::type,
+    QualType T = getTupleLikeElementType(S, Loc, I, DecompType);
+    if (T.isNull())
+      return true;
+
+    //   each vi is a variable of type "reference to T" initialized with the
+    //   initializer, where the reference is an lvalue reference if the
+    //   initializer is an lvalue and an rvalue reference otherwise
+    QualType RefType =
+        S.BuildReferenceType(T, E.get()->isLValue(), Loc, B->getDeclName());
+    if (RefType.isNull())
+      return true;
+
+    InitializedEntity Entity =
+        InitializedEntity::InitializeBinding(ParentEntity, B, RefType);
+    InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc);
+    InitializationSequence Seq(S, Entity, Kind, Init);
+    E = Seq.Perform(S, Entity, Kind, Init);
+    if (E.isInvalid())
+      return true;
+
+    B->setBinding(T, E.get());
+    I++;
+  }
+
+  return false;
+}
+
+/// Find the base class to decompose in a built-in decomposition of a class type.
+/// This base class search is, unfortunately, not quite like any other that we
+/// perform anywhere else in C++.
+static const CXXRecordDecl *findDecomposableBaseClass(Sema &S,
+                                                      SourceLocation Loc,
+                                                      const CXXRecordDecl *RD,
+                                                      CXXCastPath &BasePath) {
+  auto BaseHasFields = [](const CXXBaseSpecifier *Specifier,
+                          CXXBasePath &Path) {
+    return Specifier->getType()->getAsCXXRecordDecl()->hasDirectFields();
+  };
+
+  const CXXRecordDecl *ClassWithFields = nullptr;
+  if (RD->hasDirectFields())
+    // [dcl.decomp]p4:
+    //   Otherwise, all of E's non-static data members shall be public direct
+    //   members of E ...
+    ClassWithFields = RD;
+  else {
+    //   ... or of ...
+    CXXBasePaths Paths;
+    Paths.setOrigin(const_cast<CXXRecordDecl*>(RD));
+    if (!RD->lookupInBases(BaseHasFields, Paths)) {
+      // If no classes have fields, just decompose RD itself. (This will work
+      // if and only if zero bindings were provided.)
+      return RD;
+    }
+
+    CXXBasePath *BestPath = nullptr;
+    for (auto &P : Paths) {
+      if (!BestPath)
+        BestPath = &P;
+      else if (!S.Context.hasSameType(P.back().Base->getType(),
+                                      BestPath->back().Base->getType())) {
+        //   ... the same ...
+        S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members)
+          << false << RD << BestPath->back().Base->getType()
+          << P.back().Base->getType();
+        return nullptr;
+      } else if (P.Access < BestPath->Access) {
+        BestPath = &P;
+      }
+    }
+
+    //   ... unambiguous ...
+    QualType BaseType = BestPath->back().Base->getType();
+    if (Paths.isAmbiguous(S.Context.getCanonicalType(BaseType))) {
+      S.Diag(Loc, diag::err_decomp_decl_ambiguous_base)
+        << RD << BaseType << S.getAmbiguousPathsDisplayString(Paths);
+      return nullptr;
+    }
+
+    //   ... public base class of E.
+    if (BestPath->Access != AS_public) {
+      S.Diag(Loc, diag::err_decomp_decl_non_public_base)
+        << RD << BaseType;
+      for (auto &BS : *BestPath) {
+        if (BS.Base->getAccessSpecifier() != AS_public) {
+          S.Diag(BS.Base->getLocStart(), diag::note_access_constrained_by_path)
+            << (BS.Base->getAccessSpecifier() == AS_protected)
+            << (BS.Base->getAccessSpecifierAsWritten() == AS_none);
+          break;
+        }
+      }
+      return nullptr;
+    }
+
+    ClassWithFields = BaseType->getAsCXXRecordDecl();
+    S.BuildBasePathArray(Paths, BasePath);
+  }
+
+  // The above search did not check whether the selected class itself has base
+  // classes with fields, so check that now.
+  CXXBasePaths Paths;
+  if (ClassWithFields->lookupInBases(BaseHasFields, Paths)) {
+    S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members)
+      << (ClassWithFields == RD) << RD << ClassWithFields
+      << Paths.front().back().Base->getType();
+    return nullptr;
+  }
+
+  return ClassWithFields;
+}
+
+static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings,
+                                     ValueDecl *Src, QualType DecompType,
+                                     const CXXRecordDecl *RD) {
+  CXXCastPath BasePath;
+  RD = findDecomposableBaseClass(S, Src->getLocation(), RD, BasePath);
+  if (!RD)
+    return true;
+  QualType BaseType = S.Context.getQualifiedType(S.Context.getRecordType(RD),
+                                                 DecompType.getQualifiers());
+
+  auto DiagnoseBadNumberOfBindings = [&]() -> bool {
+    unsigned NumFields = std::distance(RD->field_begin(), RD->field_end());
+    assert(Bindings.size() != NumFields);
+    S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings)
+        << DecompType << (unsigned)Bindings.size() << NumFields
+        << (NumFields < Bindings.size());
+    return true;
+  };
+
+  //   all of E's non-static data members shall be public [...] members,
+  //   E shall not have an anonymous union member, ...
+  unsigned I = 0;
+  for (auto *FD : RD->fields()) {
+    if (FD->isUnnamedBitfield())
+      continue;
+
+    if (FD->isAnonymousStructOrUnion()) {
+      S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member)
+        << DecompType << FD->getType()->isUnionType();
+      S.Diag(FD->getLocation(), diag::note_declared_at);
+      return true;
+    }
+
+    // We have a real field to bind.
+    if (I >= Bindings.size())
+      return DiagnoseBadNumberOfBindings();
+    auto *B = Bindings[I++];
+
+    SourceLocation Loc = B->getLocation();
+    if (FD->getAccess() != AS_public) {
+      S.Diag(Loc, diag::err_decomp_decl_non_public_member) << FD << DecompType;
+
+      // Determine whether the access specifier was explicit.
+      bool Implicit = true;
+      for (const auto *D : RD->decls()) {
+        if (declaresSameEntity(D, FD))
+          break;
+        if (isa<AccessSpecDecl>(D)) {
+          Implicit = false;
+          break;
+        }
+      }
+
+      S.Diag(FD->getLocation(), diag::note_access_natural)
+        << (FD->getAccess() == AS_protected) << Implicit;
+      return true;
+    }
+
+    // Initialize the binding to Src.FD.
+    ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc);
+    if (E.isInvalid())
+      return true;
+    E = S.ImpCastExprToType(E.get(), BaseType, CK_UncheckedDerivedToBase,
+                            VK_LValue, &BasePath);
+    if (E.isInvalid())
+      return true;
+    E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc,
+                                  CXXScopeSpec(), FD,
+                                  DeclAccessPair::make(FD, FD->getAccess()),
+                                  DeclarationNameInfo(FD->getDeclName(), Loc));
+    if (E.isInvalid())
+      return true;
+
+    // If the type of the member is T, the referenced type is cv T, where cv is
+    // the cv-qualification of the decomposition expression.
+    //
+    // FIXME: We resolve a defect here: if the field is mutable, we do not add
+    // 'const' to the type of the field.
+    Qualifiers Q = DecompType.getQualifiers();
+    if (FD->isMutable())
+      Q.removeConst();
+    B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get());
+  }
+
+  if (I != Bindings.size())
+    return DiagnoseBadNumberOfBindings();
+
+  return false;
+}
+
+void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD,
+                                                 InitializedEntity &Entity) {
+  QualType DecompType = DD->getType();
+
+  // If the type of the decomposition is dependent, then so is the type of
+  // each binding.
+  if (DecompType->isDependentType()) {
+    for (auto *B : DD->bindings())
+      B->setType(Context.DependentTy);
+    return;
+  }
+
+  DecompType = DecompType.getNonReferenceType();
+  ArrayRef<BindingDecl*> Bindings = DD->bindings();
+
+  // C++1z [dcl.decomp]/2:
+  //   If E is an array type [...]
+  // As an extension, we also support decomposition of built-in complex and
+  // vector types.
+  if (auto *CAT = Context.getAsConstantArrayType(DecompType)) {
+    if (checkArrayDecomposition(*this, Bindings, DD, DecompType, CAT))
+      DD->setInvalidDecl();
+    return;
+  }
+  if (auto *VT = DecompType->getAs<VectorType>()) {
+    if (checkVectorDecomposition(*this, Bindings, DD, DecompType, VT))
+      DD->setInvalidDecl();
+    return;
+  }
+  if (auto *CT = DecompType->getAs<ComplexType>()) {
+    if (checkComplexDecomposition(*this, Bindings, DD, DecompType, CT))
+      DD->setInvalidDecl();
+    return;
+  }
+
+  // C++1z [dcl.decomp]/3:
+  //   if the expression std::tuple_size<E>::value is a well-formed integral
+  //   constant expression, [...]
+  llvm::APSInt TupleSize(32);
+  switch (isTupleLike(*this, DD->getLocation(), DecompType, TupleSize)) {
+  case IsTupleLike::Error:
+    DD->setInvalidDecl();
+    return;
+
+  case IsTupleLike::TupleLike:
+    if (checkTupleLikeDecomposition(*this, Bindings, DD, Entity, DecompType,
+                                    TupleSize))
+      DD->setInvalidDecl();
+    return;
+
+  case IsTupleLike::NotTupleLike:
+    break;
+  }
+
+  // C++1z [dcl.dcl]/8:
+  //   [E shall be of array or non-union class type]
+  CXXRecordDecl *RD = DecompType->getAsCXXRecordDecl();
+  if (!RD || RD->isUnion()) {
+    Diag(DD->getLocation(), diag::err_decomp_decl_unbindable_type)
+        << DD << !RD << DecompType;
+    DD->setInvalidDecl();
+    return;
+  }
+
+  // C++1z [dcl.decomp]/4:
+  //   all of E's non-static data members shall be [...] direct members of
+  //   E or of the same unambiguous public base class of E, ...
+  if (checkMemberDecomposition(*this, Bindings, DD, DecompType, RD))
+    DD->setInvalidDecl();
+}
+
 /// \brief Merge the exception specifications of two variable declarations.
 ///
 /// This is called when there's a redeclaration of a VarDecl. The function

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Aug 11 17:25:46 2016
@@ -1788,6 +1788,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, Qua
       E->setObjectKind(OK_BitField);
   }
 
+  // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier
+  // designates a bit-field.
+  if (auto *BD = dyn_cast<BindingDecl>(D))
+    if (auto *BE = BD->getBinding())
+      E->setObjectKind(BE->getObjectKind());
+
   return E;
 }
 
@@ -2943,7 +2949,6 @@ ExprResult Sema::BuildDeclarationNameExp
     case Decl::VarTemplateSpecialization:
     case Decl::VarTemplatePartialSpecialization:
     case Decl::Decomposition:
-    case Decl::Binding:
     case Decl::OMPCapturedExpr:
       // In C, "extern void blah;" is valid and is an r-value.
       if (!getLangOpts().CPlusPlus &&
@@ -2971,6 +2976,14 @@ ExprResult Sema::BuildDeclarationNameExp
       
       break;
     }
+
+    case Decl::Binding: {
+      // These are always lvalues.
+      valueKind = VK_LValue;
+      type = type.getNonReferenceType();
+      // FIXME: Adjust cv-qualifiers for capture.
+      break;
+    }
         
     case Decl::Function: {
       if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) {
@@ -10580,7 +10593,8 @@ QualType Sema::CheckAddressOfOperand(Exp
           return MPTy;
         }
       }
-    } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl))
+    } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) &&
+               !isa<BindingDecl>(dcl))
       llvm_unreachable("Unknown/unexpected decl type");
   }
 

Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprMember.cpp Thu Aug 11 17:25:46 2016
@@ -771,12 +771,6 @@ Sema::BuildMemberReferenceExpr(Expr *Bas
                                   false, ExtraArgs);
 }
 
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
-                        SourceLocation OpLoc, const CXXScopeSpec &SS,
-                        FieldDecl *Field, DeclAccessPair FoundDecl,
-                        const DeclarationNameInfo &MemberNameInfo);
-
 ExprResult
 Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS,
                                                SourceLocation loc,
@@ -862,7 +856,7 @@ Sema::BuildAnonymousStructUnionMemberRef
     // Make a nameInfo that properly uses the anonymous name.
     DeclarationNameInfo memberNameInfo(field->getDeclName(), loc);
 
-    result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer,
+    result = BuildFieldReferenceExpr(result, baseObjectIsPointer,
                                      SourceLocation(), EmptySS, field,
                                      foundDecl, memberNameInfo).get();
     if (!result)
@@ -883,9 +877,10 @@ Sema::BuildAnonymousStructUnionMemberRef
         DeclAccessPair::make(field, field->getAccess());
 
     result =
-        BuildFieldReferenceExpr(*this, result, /*isarrow*/ false,
-                                SourceLocation(), (FI == FEnd ? SS : EmptySS),
-                                field, fakeFoundDecl, memberNameInfo).get();
+        BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(),
+                                (FI == FEnd ? SS : EmptySS), field,
+                                fakeFoundDecl, memberNameInfo)
+            .get();
   }
   
   return result;
@@ -1153,8 +1148,8 @@ Sema::BuildMemberReferenceExpr(Expr *Bas
     return ExprError();
 
   if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl))
-    return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, OpLoc, SS, FD,
-                                   FoundDecl, MemberNameInfo);
+    return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl,
+                                   MemberNameInfo);
 
   if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl))
     return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD,
@@ -1757,11 +1752,11 @@ ExprResult Sema::ActOnMemberAccessExpr(S
                                   NameInfo, TemplateArgs, S, &ExtraArgs);
 }
 
-static ExprResult
-BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
-                        SourceLocation OpLoc, const CXXScopeSpec &SS,
-                        FieldDecl *Field, DeclAccessPair FoundDecl,
-                        const DeclarationNameInfo &MemberNameInfo) {
+ExprResult
+Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
+                              SourceLocation OpLoc, const CXXScopeSpec &SS,
+                              FieldDecl *Field, DeclAccessPair FoundDecl,
+                              const DeclarationNameInfo &MemberNameInfo) {
   // x.a is an l-value if 'a' has a reference type. Otherwise:
   // x.a is an l-value/x-value/pr-value if the base is (and note
   //   that *x is always an l-value), except that if the base isn't
@@ -1795,36 +1790,34 @@ BuildFieldReferenceExpr(Sema &S, Expr *B
     // except that 'mutable' members don't pick up 'const'.
     if (Field->isMutable()) BaseQuals.removeConst();
 
-    Qualifiers MemberQuals
-    = S.Context.getCanonicalType(MemberType).getQualifiers();
+    Qualifiers MemberQuals =
+        Context.getCanonicalType(MemberType).getQualifiers();
 
     assert(!MemberQuals.hasAddressSpace());
 
-
     Qualifiers Combined = BaseQuals + MemberQuals;
     if (Combined != MemberQuals)
-      MemberType = S.Context.getQualifiedType(MemberType, Combined);
+      MemberType = Context.getQualifiedType(MemberType, Combined);
   }
 
-  S.UnusedPrivateFields.remove(Field);
+  UnusedPrivateFields.remove(Field);
 
-  ExprResult Base =
-  S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
-                                  FoundDecl, Field);
+  ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
+                                                  FoundDecl, Field);
   if (Base.isInvalid())
     return ExprError();
   MemberExpr *ME =
-      BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,
+      BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS,
                       /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
                       MemberNameInfo, MemberType, VK, OK);
 
   // Build a reference to a private copy for non-static data members in
   // non-static member functions, privatized by OpenMP constructs.
-  if (S.getLangOpts().OpenMP && IsArrow &&
-      !S.CurContext->isDependentContext() &&
+  if (getLangOpts().OpenMP && IsArrow &&
+      !CurContext->isDependentContext() &&
       isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
-    if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field))
-      return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
+    if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field))
+      return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
   }
   return ME;
 }

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Thu Aug 11 17:25:46 2016
@@ -936,6 +936,7 @@ static void warnBracedScalarInit(Sema &S
   case InitializedEntity::EK_Base:
   case InitializedEntity::EK_Delegating:
   case InitializedEntity::EK_BlockElement:
+  case InitializedEntity::EK_Binding:
     llvm_unreachable("unexpected braced scalar init");
   }
 
@@ -2895,6 +2896,7 @@ DeclarationName InitializedEntity::getNa
 
   case EK_Variable:
   case EK_Member:
+  case EK_Binding:
     return VariableOrMember->getDeclName();
 
   case EK_LambdaCapture:
@@ -2918,10 +2920,11 @@ DeclarationName InitializedEntity::getNa
   llvm_unreachable("Invalid EntityKind!");
 }
 
-DeclaratorDecl *InitializedEntity::getDecl() const {
+ValueDecl *InitializedEntity::getDecl() const {
   switch (getKind()) {
   case EK_Variable:
   case EK_Member:
+  case EK_Binding:
     return VariableOrMember;
 
   case EK_Parameter:
@@ -2957,6 +2960,7 @@ bool InitializedEntity::allowsNRVO() con
   case EK_Parameter:
   case EK_Parameter_CF_Audited:
   case EK_Member:
+  case EK_Binding:
   case EK_New:
   case EK_Temporary:
   case EK_CompoundLiteralInit:
@@ -2988,6 +2992,7 @@ unsigned InitializedEntity::dumpImpl(raw
   case EK_Result: OS << "Result"; break;
   case EK_Exception: OS << "Exception"; break;
   case EK_Member: OS << "Member"; break;
+  case EK_Binding: OS << "Binding"; break;
   case EK_New: OS << "New"; break;
   case EK_Temporary: OS << "Temporary"; break;
   case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;
@@ -3004,9 +3009,9 @@ unsigned InitializedEntity::dumpImpl(raw
     break;
   }
 
-  if (Decl *D = getDecl()) {
+  if (auto *D = getDecl()) {
     OS << " ";
-    cast<NamedDecl>(D)->printQualifiedName(OS);
+    D->printQualifiedName(OS);
   }
 
   OS << " '" << getType().getAsString() << "'\n";
@@ -5270,6 +5275,7 @@ getAssignmentAction(const InitializedEnt
     return Sema::AA_Casting;
 
   case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_Binding:
   case InitializedEntity::EK_ArrayElement:
   case InitializedEntity::EK_VectorElement:
   case InitializedEntity::EK_ComplexElement:
@@ -5305,6 +5311,7 @@ static bool shouldBindAsTemporary(const
   case InitializedEntity::EK_Parameter_CF_Audited:
   case InitializedEntity::EK_Temporary:
   case InitializedEntity::EK_RelatedResult:
+  case InitializedEntity::EK_Binding:
     return true;
   }
 
@@ -5326,6 +5333,7 @@ static bool shouldDestroyTemporary(const
       return false;
 
     case InitializedEntity::EK_Member:
+    case InitializedEntity::EK_Binding:
     case InitializedEntity::EK_Variable:
     case InitializedEntity::EK_Parameter:
     case InitializedEntity::EK_Parameter_CF_Audited:
@@ -5395,6 +5403,7 @@ static SourceLocation getInitializationL
     return Entity.getThrowLoc();
 
   case InitializedEntity::EK_Variable:
+  case InitializedEntity::EK_Binding:
     return Entity.getDecl()->getLocation();
 
   case InitializedEntity::EK_LambdaCapture:
@@ -5826,6 +5835,7 @@ InitializedEntityOutlivesFullExpression(
   case InitializedEntity::EK_Result:
   case InitializedEntity::EK_Exception:
   case InitializedEntity::EK_Member:
+  case InitializedEntity::EK_Binding:
   case InitializedEntity::EK_New:
   case InitializedEntity::EK_Base:
   case InitializedEntity::EK_Delegating:
@@ -5875,6 +5885,9 @@ static const InitializedEntity *getEntit
     //      ctor-initializer persists until the constructor exits.
     return Entity;
 
+  case InitializedEntity::EK_Binding:
+    return getEntityForTemporaryLifetimeExtension(Entity->getParent(), nullptr);
+
   case InitializedEntity::EK_Parameter:
   case InitializedEntity::EK_Parameter_CF_Audited:
     //   -- A temporary bound to a reference parameter in a function call
@@ -6250,7 +6263,7 @@ InitializationSequence::Perform(Sema &S,
           SourceRange Brackets;
 
           // Scavange the location of the brackets from the entity, if we can.
-          if (DeclaratorDecl *DD = Entity.getDecl()) {
+          if (auto *DD = dyn_cast_or_null<DeclaratorDecl>(Entity.getDecl())) {
             if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) {
               TypeLoc TL = TInfo->getTypeLoc();
               if (IncompleteArrayTypeLoc ArrayLoc =

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Aug 11 17:25:46 2016
@@ -2073,11 +2073,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef
     for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned());
          I < NumArgs; ++I) {
       TemplateArgument TA(Context, I, ArgTy);
-      Expr *E = SemaRef.BuildExpressionFromIntegralTemplateArgument(
-                           TA, TemplateArgs[2].getLocation())
-                    .getAs<Expr>();
-      SyntheticTemplateArgs.addArgument(
-          TemplateArgumentLoc(TemplateArgument(E), E));
+      SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc(
+          TA, ArgTy, TemplateArgs[2].getLocation()));
     }
     // The first template argument will be reused as the template decl that
     // our synthetic template arguments will be applied to.

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Aug 11 17:25:46 2016
@@ -2002,37 +2002,33 @@ static bool isSameTemplateArg(ASTContext
 ///
 /// \param Loc The source location to use for the resulting template
 /// argument.
-static TemplateArgumentLoc
-getTrivialTemplateArgumentLoc(Sema &S,
-                              const TemplateArgument &Arg,
-                              QualType NTTPType,
-                              SourceLocation Loc) {
+TemplateArgumentLoc
+Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg,
+                                    QualType NTTPType, SourceLocation Loc) {
   switch (Arg.getKind()) {
   case TemplateArgument::Null:
     llvm_unreachable("Can't get a NULL template argument here");
 
   case TemplateArgument::Type:
-    return TemplateArgumentLoc(Arg,
-                     S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
+    return TemplateArgumentLoc(
+        Arg, Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc));
 
   case TemplateArgument::Declaration: {
-    Expr *E
-      = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
-          .getAs<Expr>();
+    Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+                  .getAs<Expr>();
     return TemplateArgumentLoc(TemplateArgument(E), E);
   }
 
   case TemplateArgument::NullPtr: {
-    Expr *E
-      = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
-          .getAs<Expr>();
+    Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc)
+                  .getAs<Expr>();
     return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true),
                                E);
   }
 
   case TemplateArgument::Integral: {
-    Expr *E
-      = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
+    Expr *E =
+        BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>();
     return TemplateArgumentLoc(TemplateArgument(E), E);
   }
 
@@ -2041,18 +2037,16 @@ getTrivialTemplateArgumentLoc(Sema &S,
       NestedNameSpecifierLocBuilder Builder;
       TemplateName Template = Arg.getAsTemplate();
       if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
-        Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc);
+        Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
       else if (QualifiedTemplateName *QTN =
                    Template.getAsQualifiedTemplateName())
-        Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc);
+        Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
       
       if (Arg.getKind() == TemplateArgument::Template)
-        return TemplateArgumentLoc(Arg, 
-                                   Builder.getWithLocInContext(S.Context),
+        return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context),
                                    Loc);
-      
-      
-      return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.Context),
+
+      return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context),
                                  Loc, Loc);
     }
 
@@ -2100,7 +2094,7 @@ ConvertDeducedTemplateArgument(Sema &S,
     // argument that we can check, almost as if the user had written
     // the template argument explicitly.
     TemplateArgumentLoc ArgLoc =
-        getTrivialTemplateArgumentLoc(S, Arg, NTTPType, Info.getLocation());
+        S.getTrivialTemplateArgumentLoc(Arg, NTTPType, Info.getLocation());
 
     // Check the template argument, converting it as necessary.
     return S.CheckTemplateArgument(

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Thu Aug 11 17:25:46 2016
@@ -1748,6 +1748,12 @@ QualType Sema::BuildQualifiedType(QualTy
   if (T.isNull())
     return QualType();
 
+  // Ignore any attempt to form a cv-qualified reference.
+  if (T->isReferenceType()) {
+    Qs.removeConst();
+    Qs.removeVolatile();
+  }
+
   // Enforce C99 6.7.3p2: "Types other than pointer types derived from
   // object or incomplete types shall not be restrict-qualified."
   if (Qs.hasRestrict()) {
@@ -1789,6 +1795,11 @@ QualType Sema::BuildQualifiedType(QualTy
   if (T.isNull())
     return QualType();
 
+  // Ignore any attempt to form a cv-qualified reference.
+  if (T->isReferenceType())
+    CVRAU &=
+        ~(DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic);
+
   // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and
   // TQ_unaligned;
   unsigned CVR = CVRAU & ~(DeclSpec::TQ_atomic | DeclSpec::TQ_unaligned);

Added: cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp?rev=278435&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp Thu Aug 11 17:25:46 2016
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+int array() {
+  int arr[3] = {};
+  // FIXME: We are supposed to create an array object here and perform elementwise initialization.
+  auto [a, b, c] = arr; // expected-error {{cannot decompose non-class, non-array}}
+
+  auto &[d, e] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but only 2 names were provided}}
+  auto &[f, g, h, i] = arr; // expected-error {{type 'int [3]' decomposes into 3 elements, but 4 names were provided}}
+
+  auto &[r0, r1, r2] = arr;
+  const auto &[cr0, cr1, cr2] = arr;
+
+  //static_assert(&arr[0] == &r0);
+  //static_assert(&arr[0] == &cr0);
+  using T = int;
+  using T = decltype(r0);
+  using U = const int;
+  using U = decltype(cr0);
+
+  return r1 + cr2;
+}

Added: cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp?rev=278435&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp Thu Aug 11 17:25:46 2016
@@ -0,0 +1,203 @@
+// RUN: %clang_cc1 -std=c++1z -verify %s
+
+using size_t = decltype(sizeof(0));
+
+struct A { int x, y; };
+struct B { int x, y; };
+
+void no_tuple_size_1() { auto [x, y] = A(); } // ok, decompose elementwise
+
+namespace std { template<typename T> struct tuple_size; }
+void no_tuple_size_2() { auto [x, y] = A(); } // ok, decompose elementwise
+
+struct Bad1 {};
+template<> struct std::tuple_size<Bad1> {};
+void no_tuple_size_3() { auto [x, y] = Bad1(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad1>::value' is not a valid integral constant expression}}
+
+struct Bad2 {};
+template<> struct std::tuple_size<Bad2> { const int value = 5; };
+void no_tuple_size_4() { auto [x, y] = Bad2(); } // expected-error {{cannot decompose this type; 'std::tuple_size<Bad2>::value' is not a valid integral constant expression}}
+
+template<> struct std::tuple_size<A> { static const int value = 3; };
+template<> struct std::tuple_size<B> { enum { value = 3 }; };
+
+void no_get_1() {
+  {
+    auto [a0, a1] = A(); // expected-error {{decomposes into 3 elements}}
+    auto [b0, b1] = B(); // expected-error {{decomposes into 3 elements}}
+  }
+  auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}}
+}
+
+int get(A);
+
+void no_get_2() {
+  // FIXME: This diagnostic is not great.
+  auto [a0, a1, a2] = A(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit initialization of binding declaration 'a0'}}
+}
+
+template<int> float &get(A);
+
+void no_tuple_element_1() {
+  auto [a0, a1, a2] = A(); // expected-error-re {{'std::tuple_element<0U{{L*}}, A>::type' does not name a type}} expected-note {{in implicit}}
+}
+
+namespace std { template<size_t, typename> struct tuple_element; } // expected-note 2{{here}}
+
+void no_tuple_element_2() {
+  auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<0, A>'}} expected-note {{in implicit}}
+}
+
+template<> struct std::tuple_element<0, A> { typedef float type; };
+
+void no_tuple_element_3() {
+  auto [a0, a1, a2] = A(); // expected-error {{implicit instantiation of undefined template 'std::tuple_element<1, A>'}} expected-note {{in implicit}}
+}
+
+template<> struct std::tuple_element<1, A> { typedef float &type; };
+template<> struct std::tuple_element<2, A> { typedef const float &type; };
+
+template<int N> auto get(B) -> int (&)[N + 1];
+template<int N> struct std::tuple_element<N, B> { typedef int type[N +1 ]; };
+
+template<typename T> struct std::tuple_size<const T> : std::tuple_size<T> {};
+template<size_t N, typename T> struct std::tuple_element<N, const T> {
+  typedef const typename std::tuple_element<N, T>::type type;
+};
+
+void referenced_type() {
+  auto [a0, a1, a2] = A();
+  auto [b0, b1, b2] = B();
+
+  A a;
+  B b;
+  auto &[ar0, ar1, ar2] = a;
+  auto &[br0, br1, br2] = b;
+
+  auto &&[arr0, arr1, arr2] = A();
+  auto &&[brr0, brr1, brr2] = B();
+
+  const auto &[acr0, acr1, acr2] = A();
+  const auto &[bcr0, bcr1, bcr2] = B();
+
+
+  using Float = float;
+  using Float = decltype(a0);
+  using Float = decltype(ar0);
+  using Float = decltype(arr0);
+
+  using ConstFloat = const float;
+  using ConstFloat = decltype(acr0);
+
+  using FloatRef = float&;
+  using FloatRef = decltype(a1);
+  using FloatRef = decltype(ar1);
+  using FloatRef = decltype(arr1);
+  using FloatRef = decltype(acr1);
+
+  using ConstFloatRef = const float&;
+  using ConstFloatRef = decltype(a2);
+  using ConstFloatRef = decltype(ar2);
+  using ConstFloatRef = decltype(arr2);
+  using ConstFloatRef = decltype(acr2);
+
+
+  using Int1 = int[1];
+  using Int1 = decltype(b0);
+  using Int1 = decltype(br0);
+  using Int1 = decltype(brr0);
+
+  using ConstInt1 = const int[1];
+  using ConstInt1 = decltype(bcr0);
+
+  using Int2 = int[2];
+  using Int2 = decltype(b1);
+  using Int2 = decltype(br1);
+  using Int2 = decltype(brr1);
+
+  using ConstInt2 = const int[2];
+  using ConstInt2 = decltype(bcr1);
+
+  using Int3 = int[3];
+  using Int3 = decltype(b2);
+  using Int3 = decltype(br2);
+  using Int3 = decltype(brr2);
+
+  using ConstInt3 = const int[3];
+  using ConstInt3 = decltype(bcr2);
+}
+
+struct C { template<int> int get(); };
+template<> struct std::tuple_size<C> { static const int value = 1; };
+template<> struct std::tuple_element<0, C> { typedef int type; };
+
+int member_get() {
+  auto [c] = C();
+  using T = int;
+  using T = decltype(c);
+  return c;
+}
+
+struct D { template<int> struct get {}; }; // expected-note {{declared here}}
+template<> struct std::tuple_size<D> { static const int value = 1; };
+template<> struct std::tuple_element<0, D> { typedef D::get<0> type; };
+void member_get_class_template() {
+  auto [d] = D(); // expected-error {{cannot refer to member 'get' in 'D' with '.'}} expected-note {{in implicit init}}
+}
+
+struct E { int get(); };
+template<> struct std::tuple_size<E> { static const int value = 1; };
+template<> struct std::tuple_element<0, E> { typedef int type; };
+void member_get_non_template() {
+  // FIXME: This diagnostic is not very good.
+  auto [e] = E(); // expected-error {{no member named 'get'}} expected-note {{in implicit init}}
+}
+
+namespace ADL {
+  struct X {};
+};
+template<int> int get(ADL::X);
+template<> struct std::tuple_size<ADL::X> { static const int value = 1; };
+template<> struct std::tuple_element<0, ADL::X> { typedef int type; };
+void adl_only_bad() {
+  auto [x] = ADL::X(); // expected-error {{undeclared identifier 'get'}} expected-note {{in implicit init}}
+}
+
+template<typename ElemType, typename GetTypeLV, typename GetTypeRV>
+struct wrap {
+  template<size_t> GetTypeLV get() &;
+  template<size_t> GetTypeRV get() &&;
+};
+template<typename ET, typename GTL, typename GTR>
+struct std::tuple_size<wrap<ET, GTL, GTR>> {
+  static const int value = 1;
+};
+template<typename ET, typename GTL, typename GTR>
+struct std::tuple_element<0, wrap<ET, GTL, GTR>> {
+  using type = ET;
+};
+
+template<typename T> T &lvalue();
+
+void test_value_category() {
+  // If the declared variable is an lvalue reference, the operand to get is an
+  // lvalue. Otherwise it's an xvalue.
+  { auto [a] = wrap<int, void, int>(); }
+  { auto &[a] = lvalue<wrap<int, int, void>>(); }
+  { auto &&[a] = wrap<int, void, int>(); }
+  // If the initializer (call to get) is an lvalue, the binding is an lvalue
+  // reference to the element type. Otherwise it's an rvalue reference to the
+  // element type.
+  { auto [a] = wrap<int, void, int&>(); }
+  { auto [a] = wrap<int&, void, int&>(); }
+  { auto [a] = wrap<int&&, void, int&>(); } // ok, reference collapse to int&
+
+  { auto [a] = wrap<int, void, int&&>(); }
+  { auto [a] = wrap<int&, void, int&&>(); } // expected-error {{non-const lvalue reference to type 'int' cannot bind}} expected-note {{in implicit}}
+  { auto [a] = wrap<const int&, void, int&&>(); }
+  { auto [a] = wrap<int&&, void, int&&>(); }
+
+  { auto [a] = wrap<int, void, float&>(); } // expected-error {{cannot bind}} expected-note {{implicit}}
+  { auto [a] = wrap<const int, void, float&>(); } // ok, const int &a can bind to float
+  { auto [a] = wrap<int, void, float>(); } // ok, int &&a can bind to float
+}

Added: cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp?rev=278435&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp Thu Aug 11 17:25:46 2016
@@ -0,0 +1,173 @@
+// RUN: %clang_cc1 -std=c++1z -verify -triple i686-linux-gnu %s
+
+template<typename T, typename U> struct same;
+template<typename T> struct same<T, T> { ~same(); };
+
+struct Empty {};
+
+struct A {
+  int a;
+};
+
+namespace NonPublicMembers {
+  struct NonPublic1 {
+  protected:
+    int a; // expected-note {{declared protected here}}
+  };
+
+  struct NonPublic2 {
+  private:
+    int a; // expected-note 2{{declared private here}}
+  };
+
+  struct NonPublic3 : private A {}; // expected-note {{constrained by private inheritance}}
+
+  struct NonPublic4 : NonPublic2 {};
+
+  void test() {
+    auto [a1] = NonPublic1(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic1'}}
+    auto [a2] = NonPublic2(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic2'}}
+    auto [a3] = NonPublic3(); // expected-error {{cannot decompose members of non-public base class 'A' of 'NonPublic3'}}
+    auto [a4] = NonPublic4(); // expected-error {{cannot decompose non-public member 'a' of 'NonPublicMembers::NonPublic4'}}
+  }
+}
+
+namespace MultipleClasses {
+  struct B : A {
+    int a;
+  };
+
+  struct C { int a; };
+  struct D : A, C {};
+
+  struct E : virtual A {};
+  struct F : A, E {}; // expected-warning {{direct base 'A' is inaccessible due to ambiguity}}
+
+  struct G : virtual A {};
+  struct H : E, G {};
+
+  struct I { int i; };
+  struct J : I {};
+  struct K : I, virtual J {}; // expected-warning {{direct base 'MultipleClasses::I' is inaccessible due to ambiguity}}
+
+  struct L : virtual J {};
+  struct M : virtual J, L {};
+
+  void test() {
+    auto [b] = B(); // expected-error {{cannot decompose class type 'B': both it and its base class 'A' have non-static data members}}
+    auto [d] = D(); // expected-error {{cannot decompose class type 'D': its base classes 'A' and 'MultipleClasses::C' have non-static data members}}
+    auto [e] = E();
+    auto [f] = F(); // expected-error-re {{cannot decompose members of ambiguous base class 'A' of 'F':{{.*}}struct MultipleClasses::F -> struct A{{.*}}struct MultipleClasses::F -> struct MultipleClasses::E -> struct A}}
+    auto [h] = H(); // ok, only one (virtual) base subobject even though there are two paths to it
+    auto [k] = K(); // expected-error {{cannot decompose members of ambiguous base class 'MultipleClasses::I'}}
+    auto [m] = M(); // ok, all paths to I are through the same virtual base subobject J
+
+    same<decltype(m), int>();
+  }
+}
+
+namespace BindingTypes {
+  struct A {
+    int i = 0;
+    int &r = i;
+    const float f = i;
+    mutable volatile int mvi;
+  };
+  void e() {
+    auto [i,r,f,mvi] = A();
+
+    same<decltype(i), int>();
+    same<decltype(r), int&>();
+    same<decltype(f), const float>();
+    same<decltype(mvi), volatile int>();
+
+    same<decltype((i)), int&>();
+    same<decltype((r)), int&>();
+    same<decltype((f)), const float&>();
+    same<decltype((mvi)), volatile int&>();
+  }
+  void f() {
+    auto &&[i,r,f,mvi] = A();
+
+    same<decltype(i), int>();
+    same<decltype(r), int&>();
+    same<decltype(f), const float>();
+    same<decltype(mvi), volatile int>();
+
+    same<decltype((i)), int&>();
+    same<decltype((r)), int&>();
+    same<decltype((f)), const float&>();
+    same<decltype((mvi)), volatile int&>();
+  }
+  void g() {
+    const auto [i,r,f,mvi] = A();
+
+    same<decltype(i), const int>();
+    same<decltype(r), int&>();
+    same<decltype(f), const float>();
+    same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx
+
+    same<decltype((i)), const int&>();
+    same<decltype((r)), int&>();
+    same<decltype((f)), const float&>();
+    same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx
+  }
+  void h() {
+    typedef const A CA;
+    auto &[i,r,f,mvi] = CA(); // type of var is 'const A &'
+
+    same<decltype(i), const int>(); // not 'int', per expected resolution of DRxxx
+    same<decltype(r), int&>();
+    same<decltype(f), const float>();
+    same<decltype(mvi), volatile int>(); // not 'const volatile int', per expected resolution of DRxxx
+
+    same<decltype((i)), const int&>(); // not 'int&', per expected resolution of DRxxx
+    same<decltype((r)), int&>();
+    same<decltype((f)), const float&>();
+    same<decltype((mvi)), volatile int&>(); // not 'const volatile int&', per expected resolution of DRxxx
+  }
+  struct B {
+    mutable int i;
+  };
+  void mut() {
+    auto [i] = B();
+    const auto [ci] = B();
+    volatile auto [vi] = B();
+    same<decltype(i), int>();
+    same<decltype(ci), int>();
+    same<decltype(vi), volatile int>();
+  }
+}
+
+namespace Bitfield {
+  struct S { unsigned long long x : 4, y : 32; int z; }; // expected-note 2{{here}}
+  int f(S s) {
+    auto [a, b, c] = s;
+    unsigned long long &ra = a; // expected-error {{bit-field 'x'}}
+    unsigned long long &rb = b; // expected-error {{bit-field 'y'}}
+    int &rc = c;
+
+    // the type of the binding is the type of the field
+    same<decltype(a), unsigned long long>();
+    same<decltype(b), unsigned long long>();
+
+    // the type of the expression is an lvalue of the field type
+    // (even though a reference can't bind to the field)
+    same<decltype((a)), unsigned long long&>();
+    same<decltype((b)), unsigned long long&>();
+
+    // the expression promotes to a type large enough to hold the result
+    same<decltype(+a), int>();
+    same<decltype(+b), unsigned int>();
+    return rc;
+  }
+}
+
+namespace std_example {
+  struct S { int x1 : 2; volatile double y1; };
+  S f();
+  const auto [x, y] = f();
+
+  same<decltype((x)), const int&> same1;
+  same<decltype((y)), const volatile double&> same2;
+}

Modified: cfe/trunk/test/Parser/cxx1z-decomposition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx1z-decomposition.cpp (original)
+++ cfe/trunk/test/Parser/cxx1z-decomposition.cpp Thu Aug 11 17:25:46 2016
@@ -67,7 +67,7 @@ namespace BadSpecifiers {
     // storage-class-specifiers
     static auto &[a] = n; // expected-error {{cannot be declared 'static'}}
     thread_local auto &[b] = n; // expected-error {{cannot be declared 'thread_local'}}
-    extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}}
+    extern auto &[c] = n; // expected-error {{cannot be declared 'extern'}} expected-error {{cannot have an initializer}}
     struct S {
       mutable auto &[d] = n; // expected-error {{not permitted in this context}}
 
@@ -97,7 +97,7 @@ namespace BadSpecifiers {
     auto [e][1] = s; // expected-error {{expected ';'}} expected-error {{requires an initializer}}
 
     // FIXME: This should fire the 'misplaced array declarator' diagnostic.
-    int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}}
+    int [K] arr = {0}; // expected-error {{expected ';'}} expected-error {{cannot be declared with type 'int'}} expected-error {{decomposition declaration '[K]' requires an initializer}}
     int [5] arr = {0}; // expected-error {{place the brackets after the name}}
 
     auto *[f] = s; // expected-error {{cannot be declared with type 'auto *'}} expected-error {{incompatible initializer}}
@@ -133,3 +133,16 @@ namespace Template {
   // FIXME: There's no actual rule against this...
   template<typename T> auto [a, b, c] = n; // expected-error {{decomposition declaration template not supported}}
 }
+
+namespace Init {
+  void f() {
+    int arr[1];
+    struct S { int n; };
+    auto &[bad1]; // expected-error {{decomposition declaration '[bad1]' requires an initializer}}
+    const auto &[bad2](S{}); // expected-error {{decomposition declaration '[bad2]' cannot have a parenthesized initializer}}
+    auto &[good1] = arr;
+    auto &&[good2] = S{};
+    S [goodish3] = { 4 }; // expected-error {{cannot be declared with type 'S'}}
+    S [goodish4] { 4 }; // expected-error {{cannot be declared with type 'S'}}
+  }
+}

Modified: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Thu Aug 11 17:25:46 2016
@@ -4,7 +4,23 @@ void use_from_own_init() {
   auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}}
 }
 
-// FIXME: create correct bindings
+// As a Clang extension, _Complex can be decomposed.
+float decompose_complex(_Complex float cf) {
+  auto [re, im] = cf;
+  //static_assert(&re == &__real cf);
+  //static_assert(&im == &__imag cf);
+  return re*re + im*im;
+}
+
+// As a Clang extension, vector types can be decomposed.
+typedef float vf3 __attribute__((ext_vector_type(3)));
+float decompose_vector(vf3 v) {
+  auto [x, y, z] = v;
+  auto *p = &x; // expected-error {{address of vector element requested}}
+  return x + y + z;
+}
+
+// FIXME: by-value array copies
 // FIXME: template instantiation
 // FIXME: ast file support
 // FIXME: code generation




More information about the cfe-commits mailing list