diff options
Diffstat (limited to 'clang/include/clang')
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 2 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Action.h | 66 | ||||
| -rw-r--r-- | clang/include/clang/Parse/DeclSpec.h | 41 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Parser.h | 75 |
4 files changed, 174 insertions, 10 deletions
diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 0067061b014..fa3918205c6 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -550,6 +550,8 @@ DIAG(warn_property_type, WARNING, "property type '%0' does not match property type inherited from '%1'") /// C++ parser diagnostics +DIAG(err_expected_unqualified_id, ERROR, + "expected unqualified-id") DIAG(err_no_declarators, ERROR, "declaration does not declare anything") DIAG(err_func_def_no_params, ERROR, diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index 698feff0b94..038c8583f81 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -22,6 +22,7 @@ namespace clang { // Semantic. class DeclSpec; class ObjCDeclSpec; + class CXXScopeSpec; class Declarator; class AttributeList; struct FieldDeclarator; @@ -60,6 +61,7 @@ public: typedef void AttrTy; typedef void BaseTy; typedef void MemInitTy; + typedef void CXXScopeTy; /// ActionResult - This structure is used while parsing/acting on expressions, /// stmts, etc. It encapsulates both the object returned by the action, plus @@ -103,11 +105,54 @@ public: /// isTypeName - Return non-null if the specified identifier is a typedef name /// in the current scope. - virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S) = 0; + /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or + /// namespace) that the identifier must be a member of. + /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::". + virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS = 0) = 0; /// isCurrentClassName - Return true if the specified name is the /// name of the innermost C++ class type currently being defined. - virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S) = 0; + virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS = 0) = 0; + + /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the + /// global scope ('::'). + virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, + SourceLocation CCLoc) { + return 0; + } + + /// ActOnCXXNestedNameSpecifier - Called during parsing of a + /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now + /// we want to resolve "bar::". 'SS' is empty or the previously parsed + /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar', + /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'. + /// Returns a CXXScopeTy* object representing the C++ scope. + virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S, + const CXXScopeSpec &SS, + SourceLocation IdLoc, + SourceLocation CCLoc, + const IdentifierInfo &II) { + return 0; + } + + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global + /// scope or nested-name-specifier) is parsed, part of a declarator-id. + /// After this method is called, according to [C++ 3.4.3p3], names should be + /// looked up in the declarator-id's scope, until the declarator is parsed and + /// ActOnCXXExitDeclaratorScope is called. + /// The 'SS' should be a non-empty valid CXXScopeSpec. + virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { + } + + /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously + /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same + /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. + /// Used to indicate that names should revert to being looked up in the + /// defining scope. + virtual void ActOnCXXExitDeclaratorScope(const CXXScopeSpec &SS) { + } /// getTypeAsString - Returns a string that describes the given /// type. This callback is used in C++ to form identifiers for @@ -227,8 +272,9 @@ public: TK_Definition // Definition of a tag: 'struct foo { int X; } Y;' }; virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, - SourceLocation KWLoc, IdentifierInfo *Name, - SourceLocation NameLoc, AttributeList *Attr) { + SourceLocation KWLoc, const CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr) { // TagType is an instance of DeclSpec::TST, indicating what kind of tag this // is (struct/union/enum/class). return 0; @@ -413,9 +459,13 @@ public: /// ActOnIdentifierExpr - Parse an identifier in expression context. /// 'HasTrailingLParen' indicates whether or not the identifier has a '(' /// token immediately after it. + /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or + /// namespace) that the identifier must be a member of. + /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::". virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, - bool HasTrailingLParen) { + bool HasTrailingLParen, + const CXXScopeSpec *SS = 0) { return 0; } @@ -968,11 +1018,13 @@ public: /// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to /// determine whether the name is a typedef or not in this scope. - virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S); + virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS); /// isCurrentClassName - Always returns false, because MinimalAction /// does not support C++ classes with constructors. - virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S); + virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S, + const CXXScopeSpec *SS); /// ActOnDeclarator - If this is a typedef declarator, we modify the /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is diff --git a/clang/include/clang/Parse/DeclSpec.h b/clang/include/clang/Parse/DeclSpec.h index 76e3e7ba892..94bd839a014 100644 --- a/clang/include/clang/Parse/DeclSpec.h +++ b/clang/include/clang/Parse/DeclSpec.h @@ -385,6 +385,40 @@ private: IdentifierInfo *GetterName; // getter name of NULL if no getter IdentifierInfo *SetterName; // setter name of NULL if no setter }; + +/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope +/// specifier. +class CXXScopeSpec { + SourceRange Range; + Action::CXXScopeTy *ScopeRep; + +public: + CXXScopeSpec() : ScopeRep(0) {} + + const SourceRange &getRange() const { return Range; } + void setRange(const SourceRange &R) { Range = R; } + void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } + void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + + Action::CXXScopeTy *getScopeRep() const { return ScopeRep; } + void setScopeRep(Action::CXXScopeTy *S) { ScopeRep = S; } + + bool isEmpty() const { return !Range.isValid(); } + bool isNotEmpty() const { return !isEmpty(); } + + /// isInvalid - An error occured during parsing of the scope specifier. + bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; } + + /// isSet - A scope specifier was resolved to a valid C++ scope. + bool isSet() const { return getScopeRep() != 0; } + + void clear() { + Range = SourceRange(); + ScopeRep = 0; + } +}; /// DeclaratorChunk - One instance of this struct is used for each type in a /// declarator that is parsed. @@ -590,6 +624,7 @@ struct DeclaratorChunk { /// stack, not objects that are allocated in large quantities on the heap. class Declarator { const DeclSpec &DS; + CXXScopeSpec SS; IdentifierInfo *Identifier; SourceLocation IdentifierLoc; @@ -667,6 +702,11 @@ public: /// be shared or when in error recovery etc. DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); } + /// getCXXScopeSpec - Return the C++ scope specifier (global scope or + /// nested-name-specifier) that is part of the declarator-id. + const CXXScopeSpec &getCXXScopeSpec() const { return SS; } + CXXScopeSpec &getCXXScopeSpec() { return SS; } + TheContext getContext() const { return Context; } DeclaratorKind getKind() const { return Kind; } @@ -675,6 +715,7 @@ public: /// clear - Reset the contents of this Declarator. void clear() { + SS.clear(); Identifier = 0; IdentifierLoc = SourceLocation(); Kind = DK_Abstract; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index f9b233ca0eb..c7558dbd579 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -16,6 +16,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Parse/Action.h" +#include "clang/Parse/DeclSpec.h" #include <stack> namespace clang { @@ -75,6 +76,7 @@ public: typedef Action::TypeTy TypeTy; typedef Action::BaseTy BaseTy; typedef Action::MemInitTy MemInitTy; + typedef Action::CXXScopeTy CXXScopeTy; // Parsing methods. @@ -114,7 +116,35 @@ private: return Tok.getKind() == tok::string_literal || Tok.getKind() == tok::wide_string_literal; } + + /// isTokenCXXScopeSpecifier - True if this token is '::', or identifier with + /// '::' as next token, or a 'C++ scope annotation' token. + /// When not in C++, always returns false. + /// + bool isTokenCXXScopeSpecifier() { + return getLang().CPlusPlus && + (Tok.is(tok::coloncolon) || + Tok.is(tok::annot_cxxscope) || + (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon))); + } + /// isTokenUnqualifiedId - True if token is the start of C++ unqualified-id + /// or an identifier in C. + /// + /// unqualified-id: + /// identifier + /// [C++] operator-function-id + /// [C++] conversion-function-id + /// [C++] '~' class-name + /// [C++] template-id [TODO] + /// + bool isTokenUnqualifiedId() const { + return Tok.is(tok::identifier) || // identifier or template-id + Tok.is(tok::kw_operator) || // operator/conversion-function-id or + // template-id + (Tok.is(tok::tilde) && getLang().CPlusPlus); // '~' class-name + } + /// ConsumeToken - Consume the current 'peek token' and lex the next one. /// This does not work with all kinds of tokens: strings and specific other /// tokens must be consumed with custom methods below. This returns the @@ -215,6 +245,20 @@ private: return PP.LookAhead(0); } + /// TryAnnotateTypeOrScopeToken - If the current token position is on a + /// typename (possibly qualified in C++) or a C++ scope specifier not followed + /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens + /// with a single annotation token representing the typename or C++ scope + /// respectively. + /// This simplifies handling of C++ scope specifiers and allows efficient + /// backtracking without the need to re-parse and resolve nested-names and + /// typenames. + void TryAnnotateTypeOrScopeToken(); + + /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only + /// annotates C++ scope specifiers. + void TryAnnotateScopeToken(); + /// TentativeParsingAction - An object that is used as a kind of "tentative /// parsing transaction". It gets instantiated to mark the token position and /// after the token consumption is done, Commit() or Revert() is called to @@ -449,6 +493,11 @@ private: return ParseParenExpression(Op, CastTy, RParenLoc); } ExprResult ParseStringLiteralExpression(); + + //===--------------------------------------------------------------------===// + // C++ Expressions + ExprResult ParseCXXIdExpression(); + void ParseCXXScopeSpecifier(CXXScopeSpec &SS); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts @@ -583,8 +632,8 @@ private: void ParseStructDeclaration(DeclSpec &DS, llvm::SmallVectorImpl<FieldDeclarator> &Fields); - bool isDeclarationSpecifier() const; - bool isTypeSpecifierQualifier() const; + bool isDeclarationSpecifier(); + bool isTypeSpecifierQualifier(); bool isTypeQualifier() const; /// isDeclarationStatement - Disambiguates between a declaration or an @@ -700,6 +749,26 @@ private: TypeTy *ParseTypeName(); AttributeList *ParseAttributes(); void ParseTypeofSpecifier(DeclSpec &DS); + + /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to + /// enter a new C++ declarator scope and exit it when the function is + /// finished. + class DeclaratorScopeObj { + CXXScopeSpec &SS; + Parser &P; + public: + DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss) {} + + void EnterDeclaratorScope() { + if (SS.isSet()) + P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS); + } + + ~DeclaratorScopeObj() { + if (SS.isSet()) + P.Actions.ActOnCXXExitDeclaratorScope(SS); + } + }; /// ParseDeclarator - Parse and verify a newly-initialized declarator. void ParseDeclarator(Declarator &D); @@ -722,7 +791,7 @@ private: //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. - TypeTy *ParseClassName(); + TypeTy *ParseClassName(const CXXScopeSpec *SS = 0); void ParseClassSpecifier(DeclSpec &DS); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclTy *TagDecl); |

