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