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 /lib | |
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
Diffstat (limited to 'lib')
-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 |
11 files changed, 392 insertions, 79 deletions
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()); + SS.setRange(Tok.getAnnotationRange()); + ConsumeToken(); + return; + } + + SS.setBeginLoc(Tok.getLocation()); + + // '::' + + if (Tok.is(tok::coloncolon)) { + // Global scope. + SourceLocation CCLoc = ConsumeToken(); + SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc)); + SS.setEndLoc(CCLoc); + } + + // nested-name-specifier: + // type-name '::' + // namespace-name '::' + // nested-name-specifier identifier '::' + // nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] + + while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IdLoc = ConsumeToken(); + assert(Tok.is(tok::coloncolon) && + "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); + if (SS.isInvalid()) + continue; + + SS.setScopeRep( + Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II) ); + SS.setEndLoc(CCLoc); + } +} + +/// ParseCXXIdExpression - Handle id-expression. +/// +/// id-expression: +/// unqualified-id +/// qualified-id +/// +/// unqualified-id: +/// identifier +/// operator-function-id +/// conversion-function-id [TODO] +/// '~' class-name [TODO] +/// template-id [TODO] +/// +/// qualified-id: +/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id +/// '::' identifier +/// '::' operator-function-id +/// '::' template-id [TODO] +/// +/// nested-name-specifier: +/// type-name '::' +/// namespace-name '::' +/// nested-name-specifier identifier '::' +/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] +/// +/// NOTE: The standard specifies that, for qualified-id, the parser does not +/// expect: +/// +/// '::' conversion-function-id +/// '::' '~' class-name +/// +/// This may cause a slight inconsistency on diagnostics: +/// +/// class C {}; +/// namespace A {} +/// void f() { +/// :: A :: ~ C(); // Some Sema error about using destructor with a +/// // namespace. +/// :: ~ C(); // Some Parser error like 'unexpected ~'. +/// } +/// +/// We simplify the parser a bit and make it work like: +/// +/// qualified-id: +/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id +/// '::' unqualified-id +/// +/// That way Sema can handle and report similar errors for namespaces and the +/// global scope. +/// +Parser::ExprResult Parser::ParseCXXIdExpression() { + // qualified-id: + // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id + // '::' unqualified-id + // + CXXScopeSpec SS; + if (isTokenCXXScopeSpecifier()) + ParseCXXScopeSpecifier(SS); + + // unqualified-id: + // identifier + // operator-function-id + // conversion-function-id [TODO] + // '~' class-name [TODO] + // template-id [TODO] + // + switch (Tok.getKind()) { + default: + return Diag(Tok, diag::err_expected_unqualified_id); + + case tok::identifier: { + // Consume the identifier so that we can see if it is followed by a '('. + IdentifierInfo &II = *Tok.getIdentifierInfo(); + SourceLocation L = ConsumeToken(); + return Actions.ActOnIdentifierExpr(CurScope, L, II, + Tok.is(tok::l_paren), &SS); + } + + case tok::kw_operator: { + SourceLocation OperatorLoc = Tok.getLocation(); + if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) { + return Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II, + Tok.is(tok::l_paren), &SS); + } + // FIXME: Handle conversion-function-id. + unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, + "expected operator-function-id"); + return Diag(Tok, DiagID); + } + + } // switch. + + assert(0 && "The switch was supposed to take care everything."); +} + /// ParseCXXCasts - This handles the various ways to cast expressions to another /// type. /// @@ -207,7 +355,7 @@ Parser::ExprResult Parser::ParseCXXCondition() { /// simple-type-specifier. /// /// simple-type-specifier: -/// '::'[opt] nested-name-specifier[opt] type-name [TODO] +/// '::'[opt] nested-name-specifier[opt] type-name /// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO] /// char /// wchar_t @@ -229,6 +377,9 @@ Parser::ExprResult Parser::ParseCXXCondition() { /// typedef-name /// void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { + // Annotate typenames and C++ scope specifiers. + TryAnnotateTypeOrScopeToken(); + DS.SetRangeStart(Tok.getLocation()); const char *PrevSpec; SourceLocation Loc = Tok.getLocation(); @@ -239,10 +390,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { abort(); // type-name - case tok::identifier: { - TypeTy *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope); - assert(TypeRep && "Identifier wasn't a type-name!"); - DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, TypeRep); + case tok::annot_qualtypename: { + DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, + Tok.getAnnotationValue()); break; } @@ -287,7 +437,10 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.Finish(Diags, PP.getSourceManager(), getLang()); return; } - DS.SetRangeEnd(Tok.getLocation()); + if (Tok.is(tok::annot_qualtypename)) + DS.SetRangeEnd(Tok.getAnnotationEndLoc()); + else + DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); DS.Finish(Diags, PP.getSourceManager(), getLang()); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 3e7aeb8f1d..4f6f117f2a 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -569,6 +569,9 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, /// [GNU] restrict /// Parser::TPResult Parser::isCXXDeclarationSpecifier() { + // Annotate typenames and C++ scope specifiers. + TryAnnotateTypeOrScopeToken(); + switch (Tok.getKind()) { // decl-specifier: // storage-class-specifier @@ -634,11 +637,6 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { // simple-type-specifier: - case tok::identifier: - if (!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) - return TPResult::False(); - // FALL THROUGH. - case tok::kw_char: case tok::kw_wchar_t: case tok::kw_bool: @@ -650,6 +648,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_float: case tok::kw_double: case tok::kw_void: + case tok::annot_qualtypename: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 625da6c281..ee4cd7b554 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -706,3 +706,74 @@ Parser::ExprResult Parser::ParseSimpleAsm() { return Result; } +/// 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 Parser::TryAnnotateTypeOrScopeToken() { + if (Tok.is(tok::annot_qualtypename) || Tok.is(tok::annot_cxxscope)) + return; + + CXXScopeSpec SS; + if (isTokenCXXScopeSpecifier()) + ParseCXXScopeSpecifier(SS); + + if (Tok.is(tok::identifier)) { + TypeTy *Ty = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, &SS); + if (Ty) { + // This is a typename. Replace the current token in-place with an + // annotation type token. + Tok.setKind(tok::annot_qualtypename); + Tok.setAnnotationValue(Ty); + Tok.setAnnotationEndLoc(Tok.getLocation()); + if (SS.isNotEmpty()) // it was a C++ qualified type name. + Tok.setLocation(SS.getBeginLoc()); + + // In case the tokens were cached, have Preprocessor replace them with the + // annotation token. + PP.AnnotateCachedTokens(Tok); + return; + } + } + + if (SS.isNotEmpty()) { + // A C++ scope specifier that isn't followed by a typename. + // Push the current token back into the token stream and use an annotation + // scope token for current token. + PP.EnterToken(Tok); + Tok.setKind(tok::annot_cxxscope); + Tok.setAnnotationValue(SS.getScopeRep()); + Tok.setAnnotationRange(SS.getRange()); + + // In case the tokens were cached, have Preprocessor replace them with the + // annotation token. + PP.AnnotateCachedTokens(Tok); + } +} + +/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only +/// annotates C++ scope specifiers. +void Parser::TryAnnotateScopeToken() { + if (Tok.is(tok::annot_cxxscope)) + return; + + if (isTokenCXXScopeSpecifier()) { + CXXScopeSpec SS; + ParseCXXScopeSpecifier(SS); + + // Push the current token back into the token stream and use an annotation + // scope token for current token. + PP.EnterToken(Tok); + Tok.setKind(tok::annot_cxxscope); + Tok.setAnnotationValue(SS.getScopeRep()); + Tok.setAnnotationRange(SS.getRange()); + + // In case the tokens were cached, have Preprocessor replace them with the + // annotation token. + PP.AnnotateCachedTokens(Tok); + } +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 38f7540afe..c04f80d0ee 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -270,7 +270,8 @@ public: //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // - virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S); + virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS); virtual std::string getTypeAsString(TypeTy *Type); virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup); virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D); @@ -300,8 +301,9 @@ public: virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS); 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); DeclTy* ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK, SourceLocation KWLoc, IdentifierInfo *Name, @@ -585,7 +587,8 @@ public: // Primary Expressions. virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, - bool HasTrailingLParen); + bool HasTrailingLParen, + const CXXScopeSpec *SS = 0); virtual ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); virtual ExprResult ActOnNumericConstant(const Token &); @@ -797,7 +800,8 @@ public: //===--------------------------------------------------------------------===// // C++ Classes // - virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S); + virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS); virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl, SourceLocation LBrace); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 18d77c4a18..57a5aa8419 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -28,7 +28,8 @@ #include "llvm/ADT/StringExtras.h" using namespace clang; -Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) { +Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS) { Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, false); if (IIDecl && (isa<TypedefDecl>(IIDecl) || @@ -2067,8 +2068,9 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, /// TagType indicates what kind of tag this is. TK indicates whether this is a /// reference/declaration/definition of a tag. Sema::DeclTy *Sema::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) { // If this is a use of an existing tag, it must have a name. assert((Name != 0 || TK == TK_Definition) && "Nameless record must be a definition!"); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fe7efbae5f..2ac5804d1e 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -262,7 +262,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { /// name of the class type currently being defined. In the case of /// nested classes, this will only return true if II is the name of /// the innermost class. -bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *) { +bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, + const CXXScopeSpec *SS) { if (CXXRecordDecl *CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext)) return &II == CurDecl->getIdentifier(); else @@ -614,7 +615,7 @@ Sema::ActOnMemInitializer(DeclTy *ConstructorD, } // It didn't name a member, so see if it names a class. - TypeTy *BaseTy = isTypeName(*MemberOrBase, S); + TypeTy *BaseTy = isTypeName(*MemberOrBase, S, 0/*SS*/); if (!BaseTy) return Diag(IdLoc, diag::err_mem_init_not_member_or_class, MemberOrBase->getName(), SourceRange(IdLoc, RParenLoc)); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index d3650c8ae1..d638b8dc98 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -337,7 +337,8 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, /// identifier is used in a function call context. Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, - bool HasTrailingLParen) { + bool HasTrailingLParen, + const CXXScopeSpec *SS) { // Could be enum-constant, value decl, instance variable, etc. Decl *D = LookupDecl(&II, Decl::IDNS_Ordinary, S); |