[cfe-dev] [PATCH]: Parsing for C++ classes
Chris Lattner
clattner at apple.com
Fri Jun 20 13:05:37 PDT 2008
On Jun 20, 2008, at 7:14 AM, Argiris Kirtzidis wrote:
> I've attached patches against the latest trunk of Parser and Sema
> changes for C++ classes support.
Wow, this is looking very nice Argiris. Most of the stuff below is
nit picky details, you're making excellent progress.
> The Parser->Sema diff for "cxx-sema.patch" was kinda manually
> created to make reviewing just the Sema changes easier, so you
> cannot apply it. If you want to try out Parser+Sema changes you need
> to apply the "cxx-parser-sema.patch", which contains the unified diff.
I'll start with the parser pieces. Once those go in I'll take a look
at sema pieces, thanks! Incidentally, the plan is to get more caught
up on recent clang development this weekend. Here's hoping :)
> Here's a few more details in addition to the summary for the parser
> changes which I mentioned in the previous post:
>
> When the parser encounters an inline method definition, it lexes and
> stores its tokens so that it can parse it just after the parsing of
> the topmost class. I.e:
>
> class C {
> void m1() {}
> class NC {
> void m2() {}
> };
> };
>
> The parsing of the above class is something like this:
>
> class C {
> void m1();
> class NC {
> void m2();
> };
> };
>
> void m1() {} // of class C
> void m2() {} // of class C::NC
Right.
> For local classes, it would be like a function is defined inside
> another function. The Action module is supposed to be aware of this
> and allow it if the function being defined is an inline class method.
Makes sense.
Details:
+DIAG(err_member_initialization, ERROR,
+ "member '%0' can be initialized only if it is a static const
integral data member")
80 cols please :)
+++ include/clang/Parse/Parser.h (working copy)
template <typename ConsumeFunc>
+ bool ConsumeUntil(tok::TokenKind T, ConsumeFunc &ConFn, bool
StopAtSemi = true,
+ bool DontConsume = false) {
+ return ConsumeUntil(&T, 1, ConFn, StopAtSemi, DontConsume);
+ }
+
+ template <typename ConsumeFunc>
+ bool ConsumeUntil(const tok::TokenKind *Toks, unsigned NumToks,
+ ConsumeFunc &ConFn, bool StopAtSemi, bool
DontConsume) {
I'm fairly uncomfortable with making ConsumeUntil completely
templated. In addition to inviting code bloat, this requires a bunch
of implementation details to be in the header. Can this be changed to
take a function pointer (possibly with a void* data pointer) instead?
It looks like you're using this for "method body eating". It would
also be reasonable to have a specialized version of this that just
counts braces/parens etc. I consider SkipUntil to really be part of
the diagnostic machinery... having it be used by the parser is a bit
strange to me, and could make future extensions to it more difficult.
+/// ::[opt] nested-name-specifier template[opt] unqualified-
id ';' [TODO]
80 columns.
+ // C++ 9.2p6: A member shall not be declared to have automatic
storage
+ // duration (auto, register) or with the extern storage-class-
specifier.
+ switch (DS.getStorageClassSpec()) {
+ case DeclSpec::SCS_unspecified:
Should this code live in parser or in sema? It seems cleaner to keep
the 'analysis' code in sema as much as possible. I know we aren't
necessarily clean about this everywhere, but I think it would be
useful to avoid this if possible.
+ } else if (DS.getStorageClassSpec() == DeclSpec::SCS_static) {
+ // "static member 'A' cannot be a bit-field"
+ Diag(colonLoc, diag::err_static_not_bitfield,
+ DeclaratorInfo.getIdentifier()->getName());
+ SkipUntil(tok::comma, true, true);
+
+ } else {
+ assert(0 && "Didn't we cover all member kinds?");
How about:
+ } else {
+ assert(DS.getStorageClassSpec() == DeclSpec::SCS_static &&
+ "Didn't we cover all member kinds?");
+ // "static member 'A' cannot be a bit-field"
+ Diag(colonLoc, diag::err_static_not_bitfield,
+ DeclaratorInfo.getIdentifier()->getName());
+ SkipUntil(tok::comma, true, true);
+
+ }
which is faster in release-asserts mode and doesn't have a false path.
+ // C++ 11p3: Members of a class defined with the keyword class are
private
+ // by default. Members of a class defined with the keywords struct
or union
+ // are public by default.
+ AccessSpecifier CurAS =
+ TagType == DeclSpec::TST_struct ||
+ TagType == DeclSpec::TST_union ? AS_public
+ : AS_private;
The precedence here is non-obvious, please use an if/then/else instead
of ?: or parenthesize.
+ if (Tok.is(tok::colon))
+ ConsumeToken();
+ else
+ Diag(Tok.getLocation(), diag::err_expected_colon);
How about:
ExpectAndConsume(tok::colon, diag::err_expected_colon);
+ // C++ 9.2p2: Within the class member-specification, the class is
regarded as
+ // complete within function bodies, default arguments,
+ // exception-specifications, and constructor ctor-initializers
(including
+ // such things in nested classes).
+ //
+ // FIXME: Only function bodies are parsed correctly, fix the rest.
+ if (!(CurScope->getFlags() & Scope::CXXClassScope)) {
Is this check sufficient for nested classes? If not, please add a
fixme.
Very picky but:
+ assert(I->Toks.size() > 0 && "Empty body!");
How about !I->Toks.empty()
+ // Append the current token at the end of the new token stream
so that it
+ // doesn't get lost.
+ I->Toks.push_back(Tok);
+ PP.EnterTokenStream(&I->Toks.front(), I->Toks.size(), true,
false);
Very nice! If there are multiple methods, should this push Tok for
all of them?
+Parser::ExprResult Parser::ParseCXXThis() {
+ assert(Tok.is(tok::kw_this) && "Not 'this'!");
+ SourceLocation ThisLoc = ConsumeToken();
+ if (CurScope->getFnParent() == 0) {
+ Diag(ThisLoc, diag::err_invalid_this_at_top_level);
+ return ExprResult(true);
+ }
Should this also check for static methods? What about C functions?
Alternatively, does sema handle these checks? If so, should Sema
handle all the checks?
+/// TryParseFunctionOrCXXMethodDef - Check the parsed declarator and
continue
+/// parsing if it is a function definition.
+/// If it is a function definition it will return true and 'Res' will
hold the
+/// declaration.
+/// If it is not a function definition it will return false.
+/// If a parsing error occured, it will return true and 'Res' will
hold 0.
Please mention that on a parse error, no tokens will be consumed.
+bool Parser::TryParseFunctionOrCXXMethodDef(Declarator &DeclaratorInfo,
+ DeclTy *&Res) {
This returns a Decl plus a "success" bool. Should this return a
"DeclResult" like the existing ExprResult/StmtResult etc stuff used by
actions?
80 cols:
- Decl *decl = static_cast<Decl*>(ActOnDeclarator(GlobalScope, D, 0));
+
+ return ActOnStartOfFunctionDef(FnBodyScope,
ActOnDeclarator(GlobalScope, D, 0));
-Chris
More information about the cfe-dev
mailing list