aboutsummaryrefslogtreecommitdiff
path: root/lib/Parse/ParseExprCXX.cpp
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2008-11-08 16:45:02 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2008-11-08 16:45:02 +0000
commiteb83ecde1a822b1c38cd060a85a08c1ac9f82cf8 (patch)
tree88e967a9d871a2ea4e6d9272c20fbc057543d2c4 /lib/Parse/ParseExprCXX.cpp
parent3604e3895ecd850291b518e5a82246c888ce9d0f (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/Parse/ParseExprCXX.cpp')
-rw-r--r--lib/Parse/ParseExprCXX.cpp165
1 files changed, 159 insertions, 6 deletions
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());
}