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