diff options
Diffstat (limited to 'clang/include/clang')
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 90 | ||||
-rw-r--r-- | clang/include/clang/AST/RecursiveASTVisitor.h | 12 | ||||
-rw-r--r-- | clang/include/clang/Basic/DeclNodes.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 4 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 23 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 5 | ||||
-rw-r--r-- | clang/include/clang/Sema/DeclSpec.h | 172 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 7 |
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); |