From eccc53a0a0ed1abc7bb4c04ed9566ce0c5c63140 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 26 Oct 2008 22:36:07 +0000 Subject: [PATCH] This patch continues parser-level implementation of designators: 1. It introduces new parser level abstractions for designators that are used to communicate between parser and sema. 2. This fixes a FIXME where "identifier ':'" was considered to be a designator even if it wasn't the first in a designator list. 3. In the "identifier ':'" case, it actually builds the designator representation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58205 91177308-0d34-0410-b5e6-96231b3b80d8 --- clang.xcodeproj/project.pbxproj | 2 + include/clang/Parse/Action.h | 1 + include/clang/Parse/DeclSpec.h | 4 +- include/clang/Parse/Designator.h | 209 +++++++++++++++++++++++++++++++ include/clang/Parse/Parser.h | 3 +- lib/Parse/ParseInit.cpp | 64 ++++++---- 6 files changed, 257 insertions(+), 26 deletions(-) create mode 100644 include/clang/Parse/Designator.h diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 1c8db4c5fb..71fddf561c 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -441,6 +441,7 @@ DE3986F30CB8D50C00223765 /* IdentifierTable.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = IdentifierTable.cpp; sourceTree = ""; }; DE3B90DE0EAC5EF200D01046 /* ExtensionRAIIObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ExtensionRAIIObject.h; path = lib/Parse/ExtensionRAIIObject.h; sourceTree = ""; }; DE3B921C0EB1A81400D01046 /* SemaInherit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SemaInherit.h; path = lib/Sema/SemaInherit.h; sourceTree = ""; }; + DE3B92230EB5152000D01046 /* Designator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Designator.h; path = clang/Parse/Designator.h; sourceTree = ""; }; DE41211D0D7F1BBE0080F80A /* GRWorkList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRWorkList.h; path = clang/Analysis/PathSensitive/GRWorkList.h; sourceTree = ""; }; DE41211E0D7F1BBE0080F80A /* SymbolManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SymbolManager.h; path = clang/Analysis/PathSensitive/SymbolManager.h; sourceTree = ""; }; DE41211F0D7F1BBE0080F80A /* GRBlockCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GRBlockCounter.h; path = clang/Analysis/PathSensitive/GRBlockCounter.h; sourceTree = ""; }; @@ -764,6 +765,7 @@ 84D9A88B0C1A581300AC7ABC /* AttributeList.h */, DE06E8130A8FF9330050E87E /* Action.h */, DE17336F0B068DC60080B521 /* DeclSpec.h */, + DE3B92230EB5152000D01046 /* Designator.h */, DE1F22020A7D852A00FBF588 /* Parser.h */, DE06BECA0A854E4B0050E87E /* Scope.h */, ); diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 799fbec973..7e71c9a14b 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -29,6 +29,7 @@ namespace clang { class Scope; class Action; class Selector; + class InitListDesignations; // Lex. class Token; diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index f1734d4148..8bd95302a4 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_PARSE_SEMADECLSPEC_H -#define LLVM_CLANG_PARSE_SEMADECLSPEC_H +#ifndef LLVM_CLANG_PARSE_DECLSPEC_H +#define LLVM_CLANG_PARSE_DECLSPEC_H #include "clang/Parse/Action.h" #include "clang/Parse/AttributeList.h" diff --git a/include/clang/Parse/Designator.h b/include/clang/Parse/Designator.h new file mode 100644 index 0000000000..613eef7f07 --- /dev/null +++ b/include/clang/Parse/Designator.h @@ -0,0 +1,209 @@ +//===--- Designator.h - Initialization Designator ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines interfaces used to represent Designators in the parser and +// is the input to Actions module. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_DESIGNATOR_H +#define LLVM_CLANG_PARSE_DESIGNATOR_H + +#include "clang/Parse/Action.h" + +namespace clang { + +/// Designator - This class is a discriminated union which holds the various +/// different sorts of designators possible. A Designation is an array of +/// these. An example of a designator are things like this: +/// [8] .field [47] // C99 designation: 3 designators +/// [8 ... 47] field: // GNU extensions: 2 designators +/// These occur in initializers, e.g.: +/// int a[10] = {2, 4, [8]=9, 10}; +/// +class Designator { +public: + enum DesignatorKind { + FieldDesignator, ArrayDesignator, ArrayRangeDesignator + }; +private: + DesignatorKind Kind; + + struct FieldDesignatorInfo { + const IdentifierInfo *II; + }; + struct ArrayDesignatorInfo { + Action::ExprTy *Index; + }; + struct ArrayRangeDesignatorInfo { + Action::ExprTy *Start, *End; + }; + + union { + FieldDesignatorInfo FieldInfo; + ArrayDesignatorInfo ArrayInfo; + ArrayRangeDesignatorInfo ArrayRangeInfo; + }; + +public: + + DesignatorKind getKind() const { return Kind; } + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + const IdentifierInfo *getField() const { + assert(isFieldDesignator() && "Invalid accessor"); + return FieldInfo.II; + } + + Action::ExprTy *getArrayIndex() const { + assert(isArrayDesignator() && "Invalid accessor"); + return ArrayInfo.Index; + } + + Action::ExprTy *getArrayRangeStart() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.Start; + } + Action::ExprTy *getArrayRangeEnd() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.End; + } + + + static Designator getField(const IdentifierInfo *II) { + Designator D; + D.Kind = FieldDesignator; + D.FieldInfo.II = II; + return D; + } + + static Designator getArray(Action::ExprTy *Index) { + Designator D; + D.Kind = ArrayDesignator; + D.ArrayInfo.Index = Index; + return D; + } + + static Designator getArrayRange(Action::ExprTy *Start, Action::ExprTy *End) { + Designator D; + D.Kind = ArrayRangeDesignator; + D.ArrayRangeInfo.Start = Start; + D.ArrayRangeInfo.End = End; + return D; + } + + /// ClearExprs - Null out any expression references, which prevents them from + /// being 'delete'd later. + void ClearExprs(Action &Actions) { + switch (Kind) { + case FieldDesignator: return; + case ArrayDesignator: + ArrayInfo.Index = 0; + return; + case ArrayRangeDesignator: + ArrayRangeInfo.Start = 0; + ArrayRangeInfo.End = 0; + return; + } + } + + /// FreeExprs - Release any unclaimed memory for the expressions in this + /// designator. + void FreeExprs(Action &Actions) { + switch (Kind) { + case FieldDesignator: return; // nothing to free. + case ArrayDesignator: + Actions.DeleteExpr(getArrayIndex()); + return; + case ArrayRangeDesignator: + Actions.DeleteExpr(getArrayRangeStart()); + Actions.DeleteExpr(getArrayRangeEnd()); + return; + } + } +}; + + +/// Designation - Represent a full designation, which is a sequence of +/// designators. This class is mostly a helper for InitListDesignations. +class Designation { + friend class InitListDesignations; + + /// InitIndex - The index of the initializer expression this is for. For + /// example, if the initializer were "{ A, .foo=B, C }" a Designation would + /// exist with InitIndex=1, because element #1 has a designation. + unsigned InitIndex; + + /// Designators - The actual designators for this initializer. + llvm::SmallVector Designators; + + Designation(unsigned Idx) : InitIndex(Idx) {} +public: + + /// AddDesignator - Add a designator to the end of this list. + void AddDesignator(Designator D) { + Designators.push_back(D); + } + + /// ClearExprs - Null out any expression references, which prevents them from + /// being 'delete'd later. + void ClearExprs(Action &Actions) { + for (unsigned i = 0, e = Designators.size(); i != e; ++i) + Designators[i].ClearExprs(Actions); + } + + /// FreeExprs - Release any unclaimed memory for the expressions in this + /// designation. + void FreeExprs(Action &Actions) { + for (unsigned i = 0, e = Designators.size(); i != e; ++i) + Designators[i].FreeExprs(Actions); + } +}; + + +/// InitListDesignations - This contains all the designators for an +/// initializer list. This is somewhat like a two dimensional array of +/// Designators, but is optimized for the cases when designators are not +/// present. +class InitListDesignations { + Action &Actions; + + /// Designations - All of the designators in this init list. These are kept + /// in order sorted by their InitIndex. + llvm::SmallVector Designations; + + InitListDesignations(const InitListDesignations&); // DO NOT IMPLEMENT + void operator=(const InitListDesignations&); // DO NOT IMPLEMENT +public: + InitListDesignations(Action &A) : Actions(A) {} + + ~InitListDesignations() { + // Release any unclaimed memory for the expressions in this init list. + for (unsigned i = 0, e = Designations.size(); i != e; ++i) + Designations[i].FreeExprs(Actions); + } + + bool hasAnyDesignators() const { + return Designations.empty(); + } + + Designation &CreateDesignation(unsigned Idx) { + assert((Designations.empty() || Designations.back().InitIndex < Idx) && + "not sorted by InitIndex!"); + Designations.push_back(Designation(Idx)); + return Designations.back(); + } + +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 46a43e7608..8aa949ec2f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -480,7 +480,8 @@ private: //===--------------------------------------------------------------------===// // C99 6.7.8: Initialization. ExprResult ParseInitializer(); - ExprResult ParseInitializerWithPotentialDesignator(); + ExprResult ParseInitializerWithPotentialDesignator(InitListDesignations &D, + unsigned InitNum); //===--------------------------------------------------------------------===// // clang Expressions diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index f4073af33f..5f2dc6d8e5 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Parse/Designator.h" #include "clang/Parse/Parser.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallString.h" @@ -54,7 +55,32 @@ static bool MayBeDesignationStart(tok::TokenKind K) { /// initializer (because it is an expression). We need to consider this case /// when parsing array designators. /// -Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() { +Parser::ExprResult Parser:: +ParseInitializerWithPotentialDesignator(InitListDesignations &Designations, + unsigned InitNum) { + + // If this is the old-style GNU extension: + // designation ::= identifier ':' + // Handle it as a field designator. Otherwise, this must be the start of a + // normal expression. + if (Tok.is(tok::identifier)) { + if (NextToken().is(tok::colon)) { + Diag(Tok, diag::ext_gnu_old_style_field_designator); + + Designation &D = Designations.CreateDesignation(InitNum); + D.AddDesignator(Designator::getField(Tok.getIdentifierInfo())); + ConsumeToken(); // Eat the identifier. + + assert(Tok.is(tok::colon) && "NextToken() not working properly!"); + ConsumeToken(); + return ParseInitializer(); + } + + // Otherwise, parse the assignment-expression. + return ParseAssignmentExpression(); + } + + // Parse each designator in the designator list until we find an initializer. while (1) { switch (Tok.getKind()) { @@ -138,25 +164,6 @@ Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() { MatchRHSPunctuation(tok::r_square, StartLoc); break; } - case tok::identifier: { - // Due to the GNU "designation: identifier ':'" extension, we don't know - // whether something starting with an identifier is an - // assignment-expression or if it is an old-style structure field - // designator. - // TODO: Check that this is the first designator. - - // If this is the gross GNU extension, handle it now. - if (NextToken().is(tok::colon)) { - Diag(Tok, diag::ext_gnu_old_style_field_designator); - ConsumeToken(); // The identifier. - assert(Tok.is(tok::colon) && "NextToken() not working properly!"); - ConsumeToken(); - return ParseInitializer(); - } - - // Otherwise, parse the assignment-expression. - return ParseAssignmentExpression(); - } } } } @@ -174,6 +181,8 @@ Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() { /// initializer-list ',' designation[opt] initializer /// Parser::ExprResult Parser::ParseInitializer() { + // TODO: Split this up into ParseInitializer + ParseBraceInitializer, make + // ParseInitializer inline so that the non-brace case is short-cut. if (Tok.isNot(tok::l_brace)) return ParseAssignmentExpression(); @@ -186,7 +195,15 @@ Parser::ExprResult Parser::ParseInitializer() { // Match the '}'. return Actions.ActOnInitList(LBraceLoc, 0, 0, ConsumeBrace()); } + + /// InitExprs - This is the actual list of expressions contained in the + /// initializer. llvm::SmallVector InitExprs; + + /// ExprDesignators - For each initializer, keep track of the designator that + /// was specified for it, if any. + InitListDesignations InitExprDesignations(Actions); + bool InitExprsOk = true; while (1) { @@ -198,7 +215,8 @@ Parser::ExprResult Parser::ParseInitializer() { if (!MayBeDesignationStart(Tok.getKind())) SubElt = ParseInitializer(); else - SubElt = ParseInitializerWithPotentialDesignator(); + SubElt = ParseInitializerWithPotentialDesignator(InitExprDesignations, + InitExprs.size()); // If we couldn't parse the subelement, bail out. if (!SubElt.isInvalid) { @@ -220,7 +238,7 @@ Parser::ExprResult Parser::ParseInitializer() { // If we don't have a comma continued list, we're done. if (Tok.isNot(tok::comma)) break; - // FIXME: save comma locations. + // TODO: save comma locations if some client cares. ConsumeToken(); // Handle trailing comma. @@ -230,7 +248,7 @@ Parser::ExprResult Parser::ParseInitializer() { return Actions.ActOnInitList(LBraceLoc, &InitExprs[0], InitExprs.size(), ConsumeBrace()); - // Delete any parsed subexpressions. + // On error, delete any parsed subexpressions. for (unsigned i = 0, e = InitExprs.size(); i != e; ++i) Actions.DeleteExpr(InitExprs[i]);