summaryrefslogtreecommitdiffstats
path: root/clang/include/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang/include/clang')
-rw-r--r--clang/include/clang/AST/DeclCXX.h90
-rw-r--r--clang/include/clang/AST/RecursiveASTVisitor.h12
-rw-r--r--clang/include/clang/Basic/DeclNodes.td2
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td23
-rw-r--r--clang/include/clang/Parse/Parser.h5
-rw-r--r--clang/include/clang/Sema/DeclSpec.h172
-rw-r--r--clang/include/clang/Sema/Sema.h7
8 files changed, 285 insertions, 30 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 7c535546f44..cd42e05ace6 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -139,7 +139,6 @@ public:
static bool classofKind(Kind K) { return K == AccessSpec; }
};
-
/// \brief Represents a base class of a C++ class.
///
/// Each CXXBaseSpecifier represents a single, direct base class (or
@@ -3366,6 +3365,95 @@ public:
friend class ASTDeclReader;
};
+/// A binding in a decomposition declaration. For instance, given:
+///
+/// int n[3];
+/// auto &[a, b, c] = n;
+///
+/// a, b, and c are BindingDecls, whose bindings are the expressions
+/// x[0], x[1], and x[2] respectively, where x is the implicit
+/// DecompositionDecl of type 'int (&)[3]'.
+class BindingDecl : public ValueDecl {
+ void anchor() override;
+
+ /// The binding represented by this declaration. References to this
+ /// declaration are effectively equivalent to this expression (except
+ /// that it is only evaluated once at the point of declaration of the
+ /// binding).
+ Expr *Binding;
+
+ BindingDecl(DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id)
+ : ValueDecl(Decl::Binding, DC, IdLoc, Id, QualType()), Binding(nullptr) {}
+
+public:
+ static BindingDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation IdLoc, IdentifierInfo *Id);
+ static BindingDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ /// Get the expression to which this declaration is bound. This may be null
+ /// in two different cases: while parsing the initializer for the
+ /// decomposition declaration, and when the initializer is type-dependent.
+ Expr *getBinding() const { return Binding; }
+
+ /// Set the binding for this BindingDecl, along with its declared type (which
+ /// should be a possibly-cv-qualified form of the type of the binding, or a
+ /// reference to such a type).
+ void setBinding(QualType DeclaredType, Expr *Binding) {
+ setType(DeclaredType);
+ this->Binding = Binding;
+ }
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == Decl::Binding; }
+};
+
+/// A decomposition declaration. For instance, given:
+///
+/// int n[3];
+/// auto &[a, b, c] = n;
+///
+/// the second line declares a DecompositionDecl of type 'int (&)[3]', and
+/// three BindingDecls (named a, b, and c). An instance of this class is always
+/// unnamed, but behaves in almost all other respects like a VarDecl.
+class DecompositionDecl final
+ : public VarDecl,
+ private llvm::TrailingObjects<DecompositionDecl, BindingDecl *> {
+ void anchor() override;
+
+ /// The number of BindingDecl*s following this object.
+ unsigned NumBindings;
+
+ DecompositionDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation LSquareLoc, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC,
+ ArrayRef<BindingDecl *> Bindings)
+ : VarDecl(Decomposition, C, DC, StartLoc, LSquareLoc, nullptr, T, TInfo,
+ SC),
+ NumBindings(Bindings.size()) {
+ std::uninitialized_copy(Bindings.begin(), Bindings.end(),
+ getTrailingObjects<BindingDecl *>());
+ }
+
+public:
+ static DecompositionDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation StartLoc,
+ SourceLocation LSquareLoc,
+ QualType T, TypeSourceInfo *TInfo,
+ StorageClass S,
+ ArrayRef<BindingDecl *> Bindings);
+ static DecompositionDecl *CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned NumBindings);
+
+ ArrayRef<BindingDecl *> bindings() const {
+ return llvm::makeArrayRef(getTrailingObjects<BindingDecl *>(), NumBindings);
+ }
+
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == Decomposition; }
+
+ friend TrailingObjects;
+};
+
/// An instance of this class represents the declaration of a property
/// member. This is a Microsoft extension to C++, first introduced in
/// Visual Studio .NET 2003 as a parallel to similar features in C#
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 7f08da804ed..71d7d19fed6 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -1803,6 +1803,18 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) {
return true;
}
+DEF_TRAVERSE_DECL(DecompositionDecl, {
+ TRY_TO(TraverseVarHelper(D));
+ for (auto *Binding : D->bindings()) {
+ TRY_TO(TraverseDecl(Binding));
+ }
+})
+
+DEF_TRAVERSE_DECL(BindingDecl, {
+ if (getDerived().shouldVisitImplicitCode())
+ TRY_TO(TraverseStmt(D->getBinding()));
+})
+
DEF_TRAVERSE_DECL(MSPropertyDecl, { TRY_TO(TraverseDeclaratorHelper(D)); })
DEF_TRAVERSE_DECL(FieldDecl, {
diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td
index 4f7bbc078d9..f29c399c665 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -37,6 +37,7 @@ def Named : Decl<1>;
def EnumConstant : DDecl<Value>;
def UnresolvedUsingValue : DDecl<Value>;
def IndirectField : DDecl<Value>;
+ def Binding : DDecl<Value>;
def OMPDeclareReduction : DDecl<Value>, DeclContext;
def Declarator : DDecl<Value, 1>;
def Field : DDecl<Declarator>;
@@ -54,6 +55,7 @@ def Named : Decl<1>;
: DDecl<VarTemplateSpecialization>;
def ImplicitParam : DDecl<Var>;
def ParmVar : DDecl<Var>;
+ def Decomposition : DDecl<Var>;
def OMPCapturedExpr : DDecl<Var>;
def NonTypeTemplateParm : DDecl<Declarator>;
def Template : DDecl<Named, 1>;
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index e5c64681e48..61a28e7896a 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -355,6 +355,10 @@ def err_expected_end_of_enumerator : Error<
def err_expected_coloncolon_after_super : Error<
"expected '::' after '__super'">;
+def ext_decomp_decl_empty : ExtWarn<
+ "ISO C++1z does not allow a decomposition group to be empty">,
+ InGroup<DiagGroup<"empty-decomposition">>;
+
/// Objective-C parser diagnostics
def err_expected_minus_or_plus : Error<
"method type specifier must start with '-' or '+'">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 129ebb27ed2..dacc56f86f2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -365,6 +365,26 @@ def warn_modifying_shadowing_decl :
"field of %1">,
InGroup<ShadowFieldInConstructorModified>, DefaultIgnore;
+// C++ decomposition declarations
+def err_decomp_decl_context : Error<
+ "decomposition declaration not permitted in this context">;
+def warn_cxx14_compat_decomp_decl : Warning<
+ "decomposition declarations are incompatible with "
+ "C++ standards before C++1z">, DefaultIgnore, InGroup<CXXPre1zCompat>;
+def ext_decomp_decl : ExtWarn<
+ "decomposition declarations are a C++1z extension">, InGroup<CXX1z>;
+def err_decomp_decl_spec : Error<
+ "decomposition declaration cannot be declared "
+ "%plural{1:'%1'|:with '%1' specifiers}0">;
+def err_decomp_decl_type : Error<
+ "decomposition declaration cannot be declared with type %0; "
+ "declared type must be 'auto' or reference to 'auto'">;
+def err_decomp_decl_parens : Error<
+ "decomposition declaration cannot be declared with parentheses">;
+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">;
// C++ using declarations
def err_using_requires_qualname : Error<
@@ -1756,6 +1776,9 @@ def warn_cxx98_compat_auto_type_specifier : Warning<
def err_auto_variable_cannot_appear_in_own_initializer : Error<
"variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 "
"type cannot appear in its own initializer">;
+def err_binding_cannot_appear_in_own_initializer : Error<
+ "binding %0 cannot appear in the initializer of its own "
+ "decomposition declaration">;
def err_illegal_decl_array_of_auto : Error<
"'%0' declared as array of %1">;
def err_new_array_of_auto : Error<
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 5838a447c3b..2e5390a5c0f 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -314,6 +314,10 @@ public:
return true;
}
+ SourceLocation getEndOfPreviousToken() {
+ return PP.getLocForEndOfToken(PrevTokLocation);
+ }
+
/// Retrieve the underscored keyword (_Nonnull, _Nullable) that corresponds
/// to the given nullability kind.
IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability) {
@@ -2352,6 +2356,7 @@ private:
bool AtomicAllowed = true,
bool IdentifierRequired = false);
void ParseDirectDeclarator(Declarator &D);
+ void ParseDecompositionDeclarator(Declarator &D);
void ParseParenDeclarator(Declarator &D);
void ParseFunctionDeclarator(Declarator &D,
ParsedAttributes &attrs,
diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index afcd791bca2..d48a1c2420c 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -1188,7 +1188,7 @@ struct DeclaratorChunk {
/// complete. Non-NULL indicates that there is a default argument.
CachedTokens *DefaultArgTokens;
- ParamInfo() {}
+ ParamInfo() = default;
ParamInfo(IdentifierInfo *ident, SourceLocation iloc,
Decl *param,
CachedTokens *DefArgTokens = nullptr)
@@ -1600,6 +1600,58 @@ struct DeclaratorChunk {
}
};
+/// A parsed C++17 decomposition declarator of the form
+/// '[' identifier-list ']'
+class DecompositionDeclarator {
+public:
+ struct Binding {
+ IdentifierInfo *Name;
+ SourceLocation NameLoc;
+ };
+
+private:
+ /// The locations of the '[' and ']' tokens.
+ SourceLocation LSquareLoc, RSquareLoc;
+
+ /// The bindings.
+ Binding *Bindings;
+ unsigned NumBindings : 31;
+ unsigned DeleteBindings : 1;
+
+ friend class Declarator;
+
+public:
+ DecompositionDeclarator()
+ : Bindings(nullptr), NumBindings(0), DeleteBindings(false) {}
+ DecompositionDeclarator(const DecompositionDeclarator &G) = delete;
+ DecompositionDeclarator &operator=(const DecompositionDeclarator &G) = delete;
+ ~DecompositionDeclarator() {
+ if (DeleteBindings)
+ delete[] Bindings;
+ }
+
+ void clear() {
+ LSquareLoc = RSquareLoc = SourceLocation();
+ if (DeleteBindings)
+ delete[] Bindings;
+ Bindings = nullptr;
+ NumBindings = 0;
+ DeleteBindings = false;
+ }
+
+ ArrayRef<Binding> bindings() const {
+ return llvm::makeArrayRef(Bindings, NumBindings);
+ }
+
+ bool isSet() const { return LSquareLoc.isValid(); }
+
+ SourceLocation getLSquareLoc() const { return LSquareLoc; }
+ SourceLocation getRSquareLoc() const { return RSquareLoc; }
+ SourceRange getSourceRange() const {
+ return SourceRange(LSquareLoc, RSquareLoc);
+ }
+};
+
/// \brief Described the kind of function definition (if any) provided for
/// a function.
enum FunctionDefinitionKind {
@@ -1658,6 +1710,9 @@ private:
/// \brief Where we are parsing this declarator.
TheContext Context;
+ /// The C++17 structured binding, if any. This is an alternative to a Name.
+ DecompositionDeclarator BindingGroup;
+
/// DeclTypeInfo - This holds each type that the declarator includes as it is
/// parsed. This is pushed from the identifier out, which means that element
/// #0 will be the most closely bound to the identifier, and
@@ -1679,18 +1734,6 @@ private:
/// \brief Is this Declarator a redeclaration?
unsigned Redeclaration : 1;
- /// Attrs - Attributes.
- ParsedAttributes Attrs;
-
- /// \brief The asm label, if specified.
- Expr *AsmLabel;
-
- /// InlineParams - This is a local array used for the first function decl
- /// chunk to avoid going to the heap for the common case when we have one
- /// function chunk in the declarator.
- DeclaratorChunk::ParamInfo InlineParams[16];
- bool InlineParamsUsed;
-
/// \brief true if the declaration is preceded by \c __extension__.
unsigned Extension : 1;
@@ -1700,6 +1743,23 @@ private:
/// Indicates whether this is an Objective-C 'weak' property.
unsigned ObjCWeakProperty : 1;
+ /// Indicates whether the InlineParams / InlineBindings storage has been used.
+ unsigned InlineStorageUsed : 1;
+
+ /// Attrs - Attributes.
+ ParsedAttributes Attrs;
+
+ /// \brief The asm label, if specified.
+ Expr *AsmLabel;
+
+ union {
+ /// InlineParams - This is a local array used for the first function decl
+ /// chunk to avoid going to the heap for the common case when we have one
+ /// function chunk in the declarator.
+ DeclaratorChunk::ParamInfo InlineParams[16];
+ DecompositionDeclarator::Binding InlineBindings[16];
+ };
+
/// \brief If this is the second or subsequent declarator in this declaration,
/// the location of the comma before this declarator.
SourceLocation CommaLoc;
@@ -1712,14 +1772,12 @@ private:
public:
Declarator(const DeclSpec &ds, TheContext C)
- : DS(ds), Range(ds.getSourceRange()), Context(C),
- InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
- GroupingParens(false), FunctionDefinition(FDK_Declaration),
- Redeclaration(false),
- Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
- InlineParamsUsed(false), Extension(false), ObjCIvar(false),
- ObjCWeakProperty(false) {
- }
+ : DS(ds), Range(ds.getSourceRange()), Context(C),
+ InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error),
+ GroupingParens(false), FunctionDefinition(FDK_Declaration),
+ Redeclaration(false), Extension(false), ObjCIvar(false),
+ ObjCWeakProperty(false), InlineStorageUsed(false),
+ Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr) {}
~Declarator() {
clear();
@@ -1746,6 +1804,10 @@ public:
/// \brief Retrieve the name specified by this declarator.
UnqualifiedId &getName() { return Name; }
+
+ const DecompositionDeclarator &getDecompositionDeclarator() const {
+ return BindingGroup;
+ }
TheContext getContext() const { return Context; }
@@ -1789,13 +1851,14 @@ public:
SS.clear();
Name.clear();
Range = DS.getSourceRange();
-
+ BindingGroup.clear();
+
for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i)
DeclTypeInfo[i].destroy();
DeclTypeInfo.clear();
Attrs.clear();
AsmLabel = nullptr;
- InlineParamsUsed = false;
+ InlineStorageUsed = false;
ObjCIvar = false;
ObjCWeakProperty = false;
CommaLoc = SourceLocation();
@@ -1906,6 +1969,45 @@ public:
llvm_unreachable("unknown context kind!");
}
+ /// Return true if the context permits a C++17 decomposition declarator.
+ bool mayHaveDecompositionDeclarator() const {
+ switch (Context) {
+ case FileContext:
+ // FIXME: It's not clear that the proposal meant to allow file-scope
+ // structured bindings, but it does.
+ case BlockContext:
+ case ForContext:
+ case InitStmtContext:
+ return true;
+
+ case ConditionContext:
+ case MemberContext:
+ case PrototypeContext:
+ case TemplateParamContext:
+ // Maybe one day...
+ return false;
+
+ // These contexts don't allow any kind of non-abstract declarator.
+ case KNRTypeListContext:
+ case TypeNameContext:
+ case AliasDeclContext:
+ case AliasTemplateContext:
+ case LambdaExprParameterContext:
+ case ObjCParameterContext:
+ case ObjCResultContext:
+ case CXXNewContext:
+ case CXXCatchContext:
+ case ObjCCatchContext:
+ case BlockLiteralContext:
+ case LambdaExprContext:
+ case ConversionIdContext:
+ case TemplateTypeArgContext:
+ case TrailingReturnContext:
+ return false;
+ }
+ llvm_unreachable("unknown context kind!");
+ }
+
/// mayBeFollowedByCXXDirectInit - Return true if the declarator can be
/// followed by a C++ direct initializer, e.g. "int x(1);".
bool mayBeFollowedByCXXDirectInit() const {
@@ -1959,14 +2061,22 @@ public:
}
/// isPastIdentifier - Return true if we have parsed beyond the point where
- /// the
+ /// the name would appear. (This may happen even if we haven't actually parsed
+ /// a name, perhaps because this context doesn't require one.)
bool isPastIdentifier() const { return Name.isValid(); }
/// hasName - Whether this declarator has a name, which might be an
/// identifier (accessible via getIdentifier()) or some kind of
- /// special C++ name (constructor, destructor, etc.).
- bool hasName() const {
- return Name.getKind() != UnqualifiedId::IK_Identifier || Name.Identifier;
+ /// special C++ name (constructor, destructor, etc.), or a structured
+ /// binding (which is not exactly a name, but occupies the same position).
+ bool hasName() const {
+ return Name.getKind() != UnqualifiedId::IK_Identifier || Name.Identifier ||
+ isDecompositionDeclarator();
+ }
+
+ /// Return whether this declarator is a decomposition declarator.
+ bool isDecompositionDeclarator() const {
+ return BindingGroup.isSet();
}
IdentifierInfo *getIdentifier() const {
@@ -1981,7 +2091,13 @@ public:
void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) {
Name.setIdentifier(Id, IdLoc);
}
-
+
+ /// Set the decomposition bindings for this declarator.
+ void
+ setDecompositionBindings(SourceLocation LSquareLoc,
+ ArrayRef<DecompositionDeclarator::Binding> Bindings,
+ SourceLocation RSquareLoc);
+
/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to
/// EndLoc, which should be the last token of the chunk.
void AddTypeInfo(const DeclaratorChunk &TI,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index cfc2a1f5956..a04ab9496fc 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -73,6 +73,7 @@ namespace clang {
class ASTWriter;
class ArrayType;
class AttributeList;
+ class BindingDecl;
class BlockDecl;
class CapturedDecl;
class CXXBasePath;
@@ -1719,7 +1720,11 @@ public:
TypeSourceInfo *TInfo,
LookupResult &Previous,
MultiTemplateParamsArg TemplateParamLists,
- bool &AddToScope);
+ bool &AddToScope,
+ ArrayRef<BindingDecl *> Bindings = None);
+ NamedDecl *
+ ActOnDecompositionDeclarator(Scope *S, Declarator &D,
+ MultiTemplateParamsArg TemplateParamLists);
// Returns true if the variable declaration is a redeclaration
bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous);
void CheckVariableDeclarationType(VarDecl *NewVD);
OpenPOWER on IntegriCloud