diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2008-11-08 16:45:02 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2008-11-08 16:45:02 +0000 |
commit | eb83ecde1a822b1c38cd060a85a08c1ac9f82cf8 (patch) | |
tree | 88e967a9d871a2ea4e6d9272c20fbc057543d2c4 | |
parent | 3604e3895ecd850291b518e5a82246c888ce9d0f (diff) |
Implement support for C++ nested-name-specifiers ('foo::bar::x') in the Parser side.
No Sema functionality change, just the signatures of the Action/Sema methods.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58913 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | Driver/PrintParserCallbacks.cpp | 8 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 66 | ||||
-rw-r--r-- | include/clang/Parse/DeclSpec.h | 41 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 75 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 128 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 21 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 39 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 165 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 71 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 14 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | test/Lexer/cxx0x_keyword.cpp | 2 |
17 files changed, 572 insertions, 93 deletions
diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp index 996051a21c..adf3bed0d0 100644 --- a/Driver/PrintParserCallbacks.cpp +++ b/Driver/PrintParserCallbacks.cpp @@ -174,8 +174,9 @@ namespace { } 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). llvm::cout << __FUNCTION__ << "\n"; @@ -399,7 +400,8 @@ namespace { /// token immediately after it. virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, - bool HasTrailingLParen) { + bool HasTrailingLParen, + const CXXScopeSpec *SS) { llvm::cout << __FUNCTION__ << "\n"; return 0; } diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 0067061b01..fa3918205c 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/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/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 698feff0b9..038c8583f8 100644 --- a/include/clang/Parse/Action.h +++ b/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/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index 76e3e7ba89..94bd839a01 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/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/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f9b233ca0e..c7558dbd57 100644 --- a/include/clang/Parse/Parser.h +++ b/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); diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 2fec359ecd..58e391ee37 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -55,8 +55,11 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { /// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to /// determine whether the name is a type name (objc class name or typedef) or /// not in this scope. +/// +/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking. Action::TypeTy * -MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) { +MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS) { if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>()) if (TI->isTypeName) return TI; @@ -65,7 +68,8 @@ MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) { /// isCurrentClassName - Always returns false, because MinimalAction /// does not support C++ classes with constructors. -bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *) { +bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, + const CXXScopeSpec *) { return false; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2b18be02a3..e3094ad7c6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -13,7 +13,6 @@ #include "clang/Parse/Parser.h" #include "clang/Basic/Diagnostic.h" -#include "clang/Parse/DeclSpec.h" #include "clang/Parse/Scope.h" #include "ExtensionRAIIObject.h" #include "llvm/ADT/SmallSet.h" @@ -419,6 +418,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { const char *PrevSpec = 0; SourceLocation Loc = Tok.getLocation(); + // Only annotate C++ scope. Allow class-name as an identifier in case + // it's a constructor. + TryAnnotateScopeToken(); + switch (Tok.getKind()) { default: // Try to parse a type-specifier; if we found one, continue. @@ -430,7 +433,45 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { // specifiers. First verify that DeclSpec's are consistent. DS.Finish(Diags, PP.getSourceManager(), getLang()); return; - + + case tok::annot_cxxscope: { + if (DS.hasTypeSpecifier()) + goto DoneWithDeclSpec; + + // We are looking for a qualified typename. + if (NextToken().isNot(tok::identifier)) + goto DoneWithDeclSpec; + + CXXScopeSpec SS; + SS.setScopeRep(Tok.getAnnotationValue()); + SS.setRange(Tok.getAnnotationRange()); + + // If the next token is the name of the class type that the C++ scope + // denotes, followed by a '(', then this is a constructor declaration. + // We're done with the decl-specifiers. + if (Actions.isCurrentClassName(*NextToken().getIdentifierInfo(), + CurScope, &SS) && + GetLookAheadToken(2).is(tok::l_paren)) + goto DoneWithDeclSpec; + + TypeTy *TypeRep = Actions.isTypeName(*NextToken().getIdentifierInfo(), + CurScope, &SS); + if (TypeRep == 0) + goto DoneWithDeclSpec; + + ConsumeToken(); // The C++ scope. + + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, + TypeRep); + if (isInvalid) + break; + + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); // The typename. + + continue; + } + // typedef-name case tok::identifier: { // This identifier can only be a typedef name if we haven't already seen @@ -605,19 +646,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { /// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] bool Parser::MaybeParseTypeSpecifier(DeclSpec &DS, int& isInvalid, const char *&PrevSpec) { + // Annotate typenames and C++ scope specifiers. + TryAnnotateTypeOrScopeToken(); + SourceLocation Loc = Tok.getLocation(); switch (Tok.getKind()) { // simple-type-specifier: - case tok::identifier: { - TypeTy *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope); - if (!TypeRep) - return false; - + case tok::annot_qualtypename: { isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, - TypeRep); - DS.SetRangeEnd(Loc); - ConsumeToken(); // The identifier + Tok.getAnnotationValue()); + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + ConsumeToken(); // The typename // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id' // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an @@ -914,11 +954,15 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, /// ParseEnumSpecifier /// enum-specifier: [C99 6.7.2.2] /// 'enum' identifier[opt] '{' enumerator-list '}' -/// [C99] 'enum' identifier[opt] '{' enumerator-list ',' '}' +///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}' /// [GNU] 'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt] /// '}' attributes[opt] /// 'enum' identifier /// [GNU] 'enum' attributes[opt] identifier +/// +/// [C++] elaborated-type-specifier: +/// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier +/// void Parser::ParseEnumSpecifier(DeclSpec &DS) { assert(Tok.is(tok::kw_enum) && "Not an enum specifier"); SourceLocation StartLoc = ConsumeToken(); @@ -929,6 +973,20 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) { // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) Attr = ParseAttributes(); + + CXXScopeSpec SS; + if (isTokenCXXScopeSpecifier()) { + ParseCXXScopeSpecifier(SS); + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_expected_ident); + if (Tok.isNot(tok::l_brace)) { + // Has no name and is not a definition. + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return; + } + } + } // Must have either 'enum name' or 'enum {...}'. if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) { @@ -963,7 +1021,7 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) { else TK = Action::TK_Reference; DeclTy *TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK, StartLoc, - Name, NameLoc, Attr); + SS, Name, NameLoc, Attr); if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); @@ -1054,7 +1112,10 @@ bool Parser::isTypeQualifier() const { /// isTypeSpecifierQualifier - Return true if the current token could be the /// start of a specifier-qualifier-list. -bool Parser::isTypeSpecifierQualifier() const { +bool Parser::isTypeSpecifierQualifier() { + // Annotate typenames and C++ scope specifiers. + TryAnnotateTypeOrScopeToken(); + switch (Tok.getKind()) { default: return false; // GNU attributes support. @@ -1092,21 +1153,23 @@ bool Parser::isTypeSpecifierQualifier() const { case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: + + // typedef-name + case tok::annot_qualtypename: return true; // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'. case tok::less: return getLang().ObjC1; - - // typedef-name - case tok::identifier: - return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0; } } /// isDeclarationSpecifier() - Return true if the current token is part of a /// declaration specifier. -bool Parser::isDeclarationSpecifier() const { +bool Parser::isDeclarationSpecifier() { + // Annotate typenames and C++ scope specifiers. + TryAnnotateTypeOrScopeToken(); + switch (Tok.getKind()) { default: return false; // storage-class-specifier @@ -1154,6 +1217,9 @@ bool Parser::isDeclarationSpecifier() const { case tok::kw_virtual: case tok::kw_explicit: + // typedef-name + case tok::annot_qualtypename: + // GNU typeof support. case tok::kw_typeof: @@ -1164,10 +1230,6 @@ bool Parser::isDeclarationSpecifier() const { // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'. case tok::less: return getLang().ObjC1; - - // typedef-name - case tok::identifier: - return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0; } } @@ -1351,12 +1413,22 @@ void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) { /// /// unqualified-id: [C++ 5.1] /// identifier -/// operator-function-id [TODO] +/// operator-function-id /// conversion-function-id [TODO] /// '~' class-name /// template-id [TODO] /// void Parser::ParseDirectDeclarator(Declarator &D) { + CXXScopeSpec &SS = D.getCXXScopeSpec(); + DeclaratorScopeObj DeclScopeObj(*this, SS); + + if (D.mayHaveIdentifier() && isTokenCXXScopeSpecifier()) { + ParseCXXScopeSpecifier(SS); + // Change the declaration context for name lookup, until this function is + // exited (and the declarator has been parsed). + DeclScopeObj.EnterDeclaratorScope(); + } + // Parse the first direct-declarator seen. if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) { assert(Tok.getIdentifierInfo() && "Not an identifier?"); @@ -1407,18 +1479,20 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetConversionFunction(ConvType, II, OperatorLoc); } } - } else if (Tok.is(tok::l_paren)) { + } else if (Tok.is(tok::l_paren) && SS.isEmpty()) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' // Example: 'char (*X)' or 'int (*XX)(void)' ParseParenDeclarator(D); - } else if (D.mayOmitIdentifier()) { + } else if (D.mayOmitIdentifier() && SS.isEmpty()) { // This could be something simple like "int" (in which case the declarator // portion is empty), if an abstract-declarator is allowed. D.SetIdentifier(0, Tok.getLocation()); } else { - // Expected identifier or '('. - Diag(Tok, diag::err_expected_ident_lparen); + if (getLang().CPlusPlus) + Diag(Tok, diag::err_expected_unqualified_id); + else + Diag(Tok, diag::err_expected_ident_lparen); // Expected identifier or '('. D.SetIdentifier(0, Tok.getLocation()); } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f90469acac..752d552f11 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -138,7 +138,7 @@ Parser::DeclTy *Parser::ParseLinkage(unsigned Context) { /// identifier /// template-id [TODO] /// -Parser::TypeTy *Parser::ParseClassName() { +Parser::TypeTy *Parser::ParseClassName(const CXXScopeSpec *SS) { // Parse the class-name. // FIXME: Alternatively, parse a simple-template-id. if (Tok.isNot(tok::identifier)) { @@ -147,7 +147,7 @@ Parser::TypeTy *Parser::ParseClassName() { } // We have an identifier; check whether it is actually a type. - TypeTy *Type = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope); + TypeTy *Type = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, SS); if (!Type) { Diag(Tok.getLocation(), diag::err_expected_class_name); return 0; @@ -216,7 +216,13 @@ void Parser::ParseClassSpecifier(DeclSpec &DS) { if (Tok.is(tok::kw___attribute)) Attr = ParseAttributes(); - // FIXME: Parse the (optional) nested-name-specifier. + // Parse the (optional) nested-name-specifier. + CXXScopeSpec SS; + if (isTokenCXXScopeSpecifier()) { + ParseCXXScopeSpecifier(SS); + if (Tok.isNot(tok::identifier)) + Diag(Tok, diag::err_expected_ident); + } // Parse the (optional) class name. // FIXME: Alternatively, parse a simple-template-id. @@ -250,7 +256,7 @@ void Parser::ParseClassSpecifier(DeclSpec &DS) { } // Parse the tag portion of this. - DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, Name, + DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, NameLoc, Attr); // Parse the optional base clause (C++ only). @@ -354,13 +360,16 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclTy *ClassDecl) IsVirtual = true; } - // FIXME: Parse optional '::' and optional nested-name-specifier. + // Parse optional '::' and optional nested-name-specifier. + CXXScopeSpec SS; + if (isTokenCXXScopeSpecifier()) + ParseCXXScopeSpecifier(SS); // The location of the base class itself. SourceLocation BaseLoc = Tok.getLocation(); // Parse the class-name. - TypeTy *BaseType = ParseClassName(); + TypeTy *BaseType = ParseClassName(&SS); if (!BaseType) return true; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 4515e4b4e9..e8758e15f1 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -401,7 +401,14 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { /// conversion-function-id [TODO] /// '~' class-name [TODO] /// template-id [TODO] +/// Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { + if (getLang().CPlusPlus) { + // Annotate typenames and C++ scope specifiers. + // Used only in C++; in C let the typedef name be handled as an identifier. + TryAnnotateTypeOrScopeToken(); + } + ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); @@ -463,17 +470,9 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { case tok::kw_false: return ParseCXXBoolLiteral(); - case tok::identifier: { - if (getLang().CPlusPlus && - Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) { - // Handle C++ function-style cast, e.g. "T(4.5)" where T is a typedef for - // double. - goto HandleType; - } - - // primary-expression: identifier - // unqualified-id: identifier - // constant: enumeration-constant + case tok::identifier: { // primary-expression: identifier + // unqualified-id: identifier + // constant: enumeration-constant // Consume the identifier so that we can see if it is followed by a '('. // Function designators are allowed to be undeclared (C99 6.5.1p2), so we @@ -587,7 +586,8 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { case tok::kw_typeof: { if (!getLang().CPlusPlus) goto UnhandledToken; - HandleType: + case tok::annot_qualtypename: + assert(getLang().CPlusPlus && "Expected C++"); // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // DeclSpec DS; @@ -601,16 +601,11 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { return ParsePostfixExpressionSuffix(Res); } - case tok::kw_operator: { - SourceLocation OperatorLoc = Tok.getLocation(); - if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) { - Res = Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II, - Tok.is(tok::l_paren)); - // These can be followed by postfix-expr pieces. - return ParsePostfixExpressionSuffix(Res); - } - break; - } + case tok::annot_cxxscope: // [C++] id-expression: qualified-id + case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id + // template-id + Res = ParseCXXIdExpression(); + return ParsePostfixExpressionSuffix(Res); case tok::at: { SourceLocation AtLoc = ConsumeToken(); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 7ce136c179..2fe3bcf2db 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -16,6 +16,154 @@ #include "clang/Parse/DeclSpec.h" using namespace clang; +/// ParseCXXScopeSpecifier - Parse global scope or nested-name-specifier. +/// +/// '::'[opt] nested-name-specifier +/// '::' +/// +/// nested-name-specifier: +/// type-name '::' +/// namespace-name '::' +/// nested-name-specifier identifier '::' +/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] +/// +void Parser::ParseCXXScopeSpecifier(CXXScopeSpec &SS) { + assert(isTokenCXXScopeSpecifier() && "Not scope specifier!"); + + if (Tok.is(tok::annot_cxxscope)) { + SS.setScopeRep(Tok.getAnnotationValue()); |