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

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 17 15:04:43 PDT 2016


For posterity, Reid worked around the MSVC2013 miscompile in r278842.

On Tue, Aug 16, 2016 at 8:02 AM, Reid Kleckner <rnk at google.com> wrote:

> This p3.cpp test has been failing with MSVC 2013 since it was added:
> http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9671
>
> Relatedly, the cxx1z-decomposition.cpp test is failing at HEAD:
> http://lab.llvm.org:8011/builders/clang-x86-win2008-selfhost/builds/9744
>
> I'll try to repro and get more info.
>
> On Thu, Aug 11, 2016 at 3:25 PM, Richard Smith via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
>
>> Author: rsmith
>> Date: Thu Aug 11 17:25:46 2016
>> New Revision: 278435
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=278435&view=rev
>> Log:
>> P0217R3: Perform semantic checks and initialization for the bindings in a
>> decomposition declaration for arrays, aggregate-like structs, tuple-like
>> types, and (as an extension) for complex and vector types.
>>
>> Added:
>>     cfe/trunk/test/CXX/dcl.decl/dcl.decomp/
>>     cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p2.cpp
>>     cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p3.cpp
>>     cfe/trunk/test/CXX/dcl.decl/dcl.decomp/p4.cpp
>> Modified:
>>     cfe/trunk/include/clang/AST/CXXInheritance.h
>>     cfe/trunk/include/clang/AST/Decl.h
>>     cfe/trunk/include/clang/AST/DeclCXX.h
>>     cfe/trunk/include/clang/AST/UnresolvedSet.h
>>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>>     cfe/trunk/include/clang/Sema/Initialization.h
>>     cfe/trunk/include/clang/Sema/Sema.h
>>     cfe/trunk/lib/AST/ASTDumper.cpp
>>     cfe/trunk/lib/AST/Decl.cpp
>>     cfe/trunk/lib/AST/DeclCXX.cpp
>>     cfe/trunk/lib/AST/Expr.cpp
>>     cfe/trunk/lib/AST/ExprClassification.cpp
>>     cfe/trunk/lib/Sema/Sema.cpp
>>     cfe/trunk/lib/Sema/SemaDecl.cpp
>>     cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>>     cfe/trunk/lib/Sema/SemaExpr.cpp
>>     cfe/trunk/lib/Sema/SemaExprMember.cpp
>>     cfe/trunk/lib/Sema/SemaInit.cpp
>>     cfe/trunk/lib/Sema/SemaTemplate.cpp
>>     cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
>>     cfe/trunk/lib/Sema/SemaType.cpp
>>     cfe/trunk/test/Parser/cxx1z-decomposition.cpp
>>     cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
>>
>> Modified: cfe/trunk/include/clang/AST/CXXInheritance.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> AST/CXXInheritance.h?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/AST/CXXInheritance.h (original)
>> +++ cfe/trunk/include/clang/AST/CXXInheritance.h Thu Aug 11 17:25:46 2016
>> @@ -172,7 +172,7 @@ public:
>>    /// paths for a derived-to-base search.
>>    explicit CXXBasePaths(bool FindAmbiguities = true, bool RecordPaths =
>> true,
>>                          bool DetectVirtual = true)
>> -      : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths),
>> +      : Origin(), FindAmbiguities(FindAmbiguities),
>> RecordPaths(RecordPaths),
>>          DetectVirtual(DetectVirtual), DetectedVirtual(nullptr),
>>          NumDeclsFound(0) {}
>>
>>
>> Modified: cfe/trunk/include/clang/AST/Decl.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> AST/Decl.h?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/AST/Decl.h (original)
>> +++ cfe/trunk/include/clang/AST/Decl.h Thu Aug 11 17:25:46 2016
>> @@ -251,7 +251,7 @@ public:
>>    // FIXME: Deprecated, move clients to getName().
>>    std::string getNameAsString() const { return Name.getAsString(); }
>>
>> -  void printName(raw_ostream &os) const { os << Name; }
>> +  virtual void printName(raw_ostream &os) const;
>>
>>    /// getDeclName - Get the actual, stored name of the declaration,
>>    /// which may be a special name.
>> @@ -1025,7 +1025,7 @@ public:
>>    ///   void foo() { int x; static int y; extern int z; }
>>    ///
>>    bool isLocalVarDecl() const {
>> -    if (getKind() != Decl::Var)
>> +    if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
>>        return false;
>>      if (const DeclContext *DC = getLexicalDeclContext())
>>        return DC->getRedeclContext()->isFunctionOrMethod();
>> @@ -1040,7 +1040,7 @@ public:
>>    /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but
>>    /// excludes variables declared in blocks.
>>    bool isFunctionOrMethodVarDecl() const {
>> -    if (getKind() != Decl::Var)
>> +    if (getKind() != Decl::Var && getKind() != Decl::Decomposition)
>>        return false;
>>      const DeclContext *DC = getLexicalDeclContext()->getRedeclContext();
>>      return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block;
>>
>> Modified: cfe/trunk/include/clang/AST/DeclCXX.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> AST/DeclCXX.h?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
>> +++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Aug 11 17:25:46 2016
>> @@ -1147,6 +1147,12 @@ public:
>>    /// \note This does NOT include a check for union-ness.
>>    bool isEmpty() const { return data().Empty; }
>>
>> +  /// \brief Determine whether this class has direct non-static data
>> members.
>> +  bool hasDirectFields() const {
>> +    auto &D = data();
>> +    return D.HasPublicFields || D.HasProtectedFields ||
>> D.HasPrivateFields;
>> +  }
>> +
>>    /// Whether this class is polymorphic (C++ [class.virtual]),
>>    /// which means that the class contains or inherits a virtual function.
>>    bool isPolymorphic() const { return data().Polymorphic; }
>> @@ -3451,6 +3457,8 @@ public:
>>      return llvm::makeArrayRef(getTrailingObjects<BindingDecl *>(),
>> NumBindings);
>>    }
>>
>> +  void printName(raw_ostream &os) const override;
>> +
>>    static bool classof(const Decl *D) { return classofKind(D->getKind());
>> }
>>    static bool classofKind(Kind K) { return K == Decomposition; }
>>
>>
>> Modified: cfe/trunk/include/clang/AST/UnresolvedSet.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> AST/UnresolvedSet.h?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/AST/UnresolvedSet.h (original)
>> +++ cfe/trunk/include/clang/AST/UnresolvedSet.h Thu Aug 11 17:25:46 2016
>> @@ -38,7 +38,7 @@ class UnresolvedSetIterator : public llv
>>        : iterator_adaptor_base(const_cast<DeclAccessPair *>(Iter)) {}
>>
>>  public:
>> -  UnresolvedSetIterator() {}
>> +  UnresolvedSetIterator() = default;
>>
>>    NamedDecl *getDecl() const { return I->getDecl(); }
>>    void setDecl(NamedDecl *ND) const { return I->setDecl(ND); }
>>
>> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Basic/DiagnosticSemaKinds.td?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
>> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Aug 11
>> 17:25:46 2016
>> @@ -385,6 +385,40 @@ def err_decomp_decl_template : Error<
>>    "decomposition declaration template not supported">;
>>  def err_decomp_decl_not_alone : Error<
>>    "decomposition declaration must be the only declaration in its group">;
>> +def err_decomp_decl_requires_init : Error<
>> +  "decomposition declaration %0 requires an initializer">;
>> +def err_decomp_decl_paren_init : Error<
>> +  "decomposition declaration %0 cannot have a parenthesized
>> initializer">;
>> +def err_decomp_decl_wrong_number_bindings : Error<
>> +  "type %0 decomposes into %2 elements, but %select{only |}3%1 "
>> +  "names were provided">;
>> +def err_decomp_decl_unbindable_type : Error<
>> +  "cannot decompose %select{union|non-class, non-array}1 type %2">;
>> +def err_decomp_decl_multiple_bases_with_members : Error<
>> +  "cannot decompose class type %1: "
>> +  "%select{its base classes %2 and|both it and its base class}0 %3 "
>> +  "have non-static data members">;
>> +def err_decomp_decl_ambiguous_base : Error<
>> +  "cannot decompose members of ambiguous base class %1 of %0:%2">;
>> +def err_decomp_decl_non_public_base : Error<
>> +  "cannot decompose members of non-public base class %1 of %0">;
>> +def err_decomp_decl_non_public_member : Error<
>> +  "cannot decompose non-public member %0 of %1">;
>> +def err_decomp_decl_anon_union_member : Error<
>> +  "cannot decompose class type %1 because it has an anonymous "
>> +  "%select{struct|union} member">;
>> +def err_decomp_decl_std_tuple_element_not_specialized : Error<
>> +  "cannot decompose this type; 'std::tuple_element<%0>::type' "
>> +  "does not name a type">;
>> +def err_decomp_decl_std_tuple_size_not_constant : Error<
>> +  "cannot decompose this type; 'std::tuple_size<%0>::value' "
>> +  "is not a valid integral constant expression">;
>> +def note_in_binding_decl_init : Note<
>> +  "in implicit initialization of binding declaration %0">;
>> +
>> +def err_std_type_trait_not_class_template : Error<
>> +  "unsupported standard library implementation: "
>> +  "'std::%0' is not a class template">;
>>
>>  // C++ using declarations
>>  def err_using_requires_qualname : Error<
>>
>> Modified: cfe/trunk/include/clang/Sema/Initialization.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Sema/Initialization.h?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Sema/Initialization.h (original)
>> +++ cfe/trunk/include/clang/Sema/Initialization.h Thu Aug 11 17:25:46
>> 2016
>> @@ -84,7 +84,10 @@ public:
>>      EK_RelatedResult,
>>      /// \brief The entity being initialized is a function parameter;
>> function
>>      /// is member of group of audited CF APIs.
>> -    EK_Parameter_CF_Audited
>> +    EK_Parameter_CF_Audited,
>> +    /// \brief The entity being initialized is a structured binding of a
>> +    /// decomposition declaration.
>> +    EK_Binding,
>>
>>      // Note: err_init_conversion_failed in DiagnosticSemaKinds.td uses
>> this
>>      // enum as an index for its first %select.  When modifying this list,
>> @@ -126,9 +129,9 @@ private:
>>    };
>>
>>    union {
>> -    /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or
>> -    /// FieldDecl, respectively.
>> -    DeclaratorDecl *VariableOrMember;
>> +    /// \brief When Kind == EK_Variable, EK_Member or EK_Binding, the
>> VarDecl,
>> +    /// FieldDecl or BindingDecl, respectively.
>> +    ValueDecl *VariableOrMember;
>>
>>      /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where
>>      /// result type was implicitly changed to accommodate ARC semantics.
>> @@ -180,6 +183,12 @@ private:
>>      : Kind(EK_Member), Parent(Parent), Type(Member->getType()),
>>        ManglingNumber(0), VariableOrMember(Member) { }
>>
>> +  /// \brief Create the initialization entity for a binding.
>> +  InitializedEntity(BindingDecl *Binding, QualType Type,
>> +                    const InitializedEntity &Parent)
>> +    : Kind(EK_Binding), Parent(&Parent), Type(Type),
>> +      ManglingNumber(0), VariableOrMember(Binding) {}
>> +
>>    /// \brief Create the initialization entity for an array element.
>>    InitializedEntity(ASTContext &Context, unsigned Index,
>>                      const InitializedEntity &Parent);
>> @@ -314,6 +323,13 @@ public:
>>      return InitializedEntity(Context, Index, Parent);
>>    }
>>
>> +  /// \brief Create the initialization entity for a structured binding.
>> +  static InitializedEntity InitializeBinding(const InitializedEntity
>> &Parent,
>> +                                             BindingDecl *Binding,
>> +                                             QualType Type) {
>> +    return InitializedEntity(Binding, Type, Parent);
>> +  }
>> +
>>    /// \brief Create the initialization entity for a lambda capture.
>>    static InitializedEntity InitializeLambdaCapture(IdentifierInfo
>> *VarID,
>>                                                     QualType FieldType,
>> @@ -355,7 +371,7 @@ public:
>>
>>    /// \brief Retrieve the variable, parameter, or field being
>>    /// initialized.
>> -  DeclaratorDecl *getDecl() const;
>> +  ValueDecl *getDecl() const;
>>
>>    /// \brief Retrieve the ObjectiveC method being initialized.
>>    ObjCMethodDecl *getMethodDecl() const { return MethodDecl; }
>>
>> Modified: cfe/trunk/include/clang/Sema/Sema.h
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/
>> Sema/Sema.h?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/include/clang/Sema/Sema.h (original)
>> +++ cfe/trunk/include/clang/Sema/Sema.h Thu Aug 11 17:25:46 2016
>> @@ -1728,7 +1728,9 @@ public:
>>    // Returns true if the variable declaration is a redeclaration
>>    bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
>>    void CheckVariableDeclarationType(VarDecl *NewVD);
>> -  void CheckCompleteVariableDeclaration(VarDecl *var);
>> +  void CheckCompleteVariableDeclaration(VarDecl *VD, InitializedEntity
>> &Entity);
>> +  void CheckCompleteDecompositionDeclaration(DecompositionDecl *DD,
>> +                                             InitializedEntity &Entity);
>>    void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D);
>>
>>    NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D,
>> DeclContext* DC,
>> @@ -3970,6 +3972,12 @@ public:
>>                             bool SuppressQualifierCheck = false,
>>                             ActOnMemberAccessExtraArgs *ExtraArgs =
>> nullptr);
>>
>> +  ExprResult BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow,
>> +                                     SourceLocation OpLoc,
>> +                                     const CXXScopeSpec &SS, FieldDecl
>> *Field,
>> +                                     DeclAccessPair FoundDecl,
>> +                                     const DeclarationNameInfo
>> &MemberNameInfo);
>> +
>>    ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow);
>>
>>    bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType,
>> @@ -5772,6 +5780,10 @@ public:
>>                              TemplateParameterList
>> **OuterTemplateParamLists,
>>                                  SkipBodyInfo *SkipBody = nullptr);
>>
>> +  TemplateArgumentLoc getTrivialTemplateArgumentLoc(const
>> TemplateArgument &Arg,
>> +                                                    QualType NTTPType,
>> +                                                    SourceLocation Loc);
>> +
>>    void translateTemplateArguments(const ASTTemplateArgsPtr &In,
>>                                    TemplateArgumentListInfo &Out);
>>
>>
>> Modified: cfe/trunk/lib/AST/ASTDumper.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDum
>> per.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/DeclCX
>> X.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/ExprCl
>> assification.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_incomp
>> lete_type))
>>        VD->setInvalidDecl();
>>
>> -    CheckCompleteVariableDeclaration(VD);
>> +    // No initialization is performed for a tentative definition.
>> +    InitializedEntity Entity = InitializedEntity::InitializeV
>> ariable(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/SemaD
>> ecl.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->getRede
>> clContext()->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::InitializeV
>> ariable(VDecl);
>>    if (!VDecl->isInvalidDecl()) {
>> -    InitializedEntity Entity = InitializedEntity::InitializeV
>> ariable(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/SemaD
>> eclCXX.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->getRede
>> clContext()->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_nu
>> mber_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->getNumEl
>> ements()),
>> +      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.ge
>> tPrintingPolicy(),
>> +                                               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_nu
>> mber_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.C
>> ontext.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_nu
>> mber_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_uni
>> on_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/SemaE
>> xpr.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/SemaE
>> xprMember.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/SemaI
>> nit.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/SemaT
>> emplate.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.getTrivialTemplate
>> ArgumentLoc(
>> +          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/SemaT
>> emplateDeduction.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.getAsDependentTemplat
>> eName())
>> -        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(Co
>> ntext),
>>                                     Loc);
>> -
>> -
>> -      return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.
>> Context),
>> +
>> +      return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Co
>> ntext),
>>                                   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/SemaT
>> ype.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/cx
>> x1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/test/Parser/cxx1z-decomposition.cpp (original)
>> +++ cfe/trunk/test/Parser/cxx1z-decomposition.cpp Thu Aug 11 17:25:46
>> 2016
>> @@ -67,7 +67,7 @@ namespace BadSpecifiers {
>>      // storage-class-specifiers
>>      static auto &[a] = n; // expected-error {{cannot be declared
>> 'static'}}
>>      thread_local auto &[b] = n; // expected-error {{cannot be declared
>> 'thread_local'}}
>> -    extern auto &[c] = n; // expected-error {{cannot be declared
>> 'extern'}}
>> +    extern auto &[c] = n; // expected-error {{cannot be declared
>> 'extern'}} expected-error {{cannot have an initializer}}
>>      struct S {
>>        mutable auto &[d] = n; // expected-error {{not permitted in this
>> context}}
>>
>> @@ -97,7 +97,7 @@ namespace BadSpecifiers {
>>      auto [e][1] = s; // expected-error {{expected ';'}} expected-error
>> {{requires an initializer}}
>>
>>      // FIXME: This should fire the 'misplaced array declarator'
>> diagnostic.
>> -    int [K] arr = {0}; // expected-error {{expected ';'}} expected-error
>> {{cannot be declared with type 'int'}}
>> +    int [K] arr = {0}; // expected-error {{expected ';'}} expected-error
>> {{cannot be declared with type 'int'}} expected-error {{decomposition
>> declaration '[K]' requires an initializer}}
>>      int [5] arr = {0}; // expected-error {{place the brackets after the
>> name}}
>>
>>      auto *[f] = s; // expected-error {{cannot be declared with type
>> 'auto *'}} expected-error {{incompatible initializer}}
>> @@ -133,3 +133,16 @@ namespace Template {
>>    // FIXME: There's no actual rule against this...
>>    template<typename T> auto [a, b, c] = n; // expected-error
>> {{decomposition declaration template not supported}}
>>  }
>> +
>> +namespace Init {
>> +  void f() {
>> +    int arr[1];
>> +    struct S { int n; };
>> +    auto &[bad1]; // expected-error {{decomposition declaration '[bad1]'
>> requires an initializer}}
>> +    const auto &[bad2](S{}); // expected-error {{decomposition
>> declaration '[bad2]' cannot have a parenthesized initializer}}
>> +    auto &[good1] = arr;
>> +    auto &&[good2] = S{};
>> +    S [goodish3] = { 4 }; // expected-error {{cannot be declared with
>> type 'S'}}
>> +    S [goodish4] { 4 }; // expected-error {{cannot be declared with type
>> 'S'}}
>> +  }
>> +}
>>
>> Modified: cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp
>> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/
>> cxx1z-decomposition.cpp?rev=278435&r1=278434&r2=278435&view=diff
>> ============================================================
>> ==================
>> --- cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp (original)
>> +++ cfe/trunk/test/SemaCXX/cxx1z-decomposition.cpp Thu Aug 11 17:25:46
>> 2016
>> @@ -4,7 +4,23 @@ void use_from_own_init() {
>>    auto [a] = a; // expected-error {{binding 'a' cannot appear in the
>> initializer of its own decomposition declaration}}
>>  }
>>
>> -// FIXME: create correct bindings
>> +// As a Clang extension, _Complex can be decomposed.
>> +float decompose_complex(_Complex float cf) {
>> +  auto [re, im] = cf;
>> +  //static_assert(&re == &__real cf);
>> +  //static_assert(&im == &__imag cf);
>> +  return re*re + im*im;
>> +}
>> +
>> +// As a Clang extension, vector types can be decomposed.
>> +typedef float vf3 __attribute__((ext_vector_type(3)));
>> +float decompose_vector(vf3 v) {
>> +  auto [x, y, z] = v;
>> +  auto *p = &x; // expected-error {{address of vector element requested}}
>> +  return x + y + z;
>> +}
>> +
>> +// FIXME: by-value array copies
>>  // FIXME: template instantiation
>>  // FIXME: ast file support
>>  // FIXME: code generation
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160817/d161f855/attachment-0001.html>


More information about the cfe-commits mailing list