ParseClassSpecifier: can "unions" inherit?

I just noticed the following code fragment in ParseClassSpecifier:

   // Parse the tag portion of this.
   DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, Name,
                                      NameLoc, Attr);

   // Parse the optional base clause (C++ only).
   if (getLang().CPlusPlus && Tok.is(tok::colon)) {
     ParseBaseClause(TagDecl);
   }

It appears from the code that the 'if' branch can be taken even if the tag decl is a union. Is this valid in the C++ grammar? That is, can there be a "base clause" for unions in C++, and if so, what does that mean?

Hi,

I just noticed the following code fragment in ParseClassSpecifier:

  // Parse the tag portion of this.
  DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc,
Name,
                                     NameLoc, Attr);

  // Parse the optional base clause (C++ only).
  if (getLang().CPlusPlus && Tok.is(tok::colon)) {
    ParseBaseClause(TagDecl);
  }

It appears from the code that the 'if' branch can be taken even if the
tag decl is a union. Is this valid in the C++ grammar? That is, can
there be a "base clause" for unions in C++, and if so, what does that
mean?

it seems not to be allowed -- at least both gcc and clang reject it. Clang does it in ActOnBaseSpecifier in Sema:

   // C++ [class.union]p1:
   // A union shall not be used as a base class.
   if (BaseType->isUnionType()) {
     Diag(BaseLoc, diag::err_union_as_base_class, SpecifierRange);
     return;
   }

Nico

Hi,

I just noticed the following code fragment in ParseClassSpecifier:

// Parse the tag portion of this.
DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc,
Name,
                                    NameLoc, Attr);

// Parse the optional base clause (C++ only).
if (getLang().CPlusPlus && Tok.is(tok::colon)) {
   ParseBaseClause(TagDecl);
}

It appears from the code that the 'if' branch can be taken even if the
tag decl is a union. Is this valid in the C++ grammar? That is, can
there be a "base clause" for unions in C++, and if so, what does that
mean?

it seems not to be allowed -- at least both gcc and clang reject it.
Clang does it in ActOnBaseSpecifier in Sema:

  // C++ [class.union]p1:
  // A union shall not be used as a base class.
  if (BaseType->isUnionType()) {
    Diag(BaseLoc, diag::err_union_as_base_class, SpecifierRange);
    return;
  }

That's odd - it seems like this should be diagnosed by the parser. Since I'm not very familiar with all the "challenges" of implementing C++:-), I'll understand if this isn't convenient.

snaroff

In the C++ grammar, unions can have base classes, but it's
semantically incorrect according to [class.union]p1. So, the parser
parses it and Sema gives an error (see Sema::ActOnBaseSpecifier).

  - Doug

Okay, that makes sense. If the Parser is suppose to strictly follow the grammar then it makes sense why the error is handled in Sema.

There's a philosophy behind here, too: if we can parse it
unambiguously because it's obvious what the user was trying to do,
it's better to parse it and give an error in Sema rather than fail to
parse it.

  - Doug

Ted Kremenek wrote:

I just noticed the following code fragment in ParseClassSpecifier:

   // Parse the tag portion of this.
   DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, Name,
                                      NameLoc, Attr);

   // Parse the optional base clause (C++ only).
   if (getLang().CPlusPlus && Tok.is(tok::colon)) {
     ParseBaseClause(TagDecl);
   }

It appears from the code that the 'if' branch can be taken even if the tag decl is a union. Is this valid in the C++ grammar? That is, can there be a "base clause" for unions in C++, and if so, what does that mean?
  
It gets flagged as error by Sema. In

steve naroff wrote:

Hi,

I just noticed the following code fragment in ParseClassSpecifier:

// Parse the tag portion of this.
DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc,
Name,
                                    NameLoc, Attr);

// Parse the optional base clause (C++ only).
if (getLang().CPlusPlus && Tok.is(tok::colon)) {
   ParseBaseClause(TagDecl);
}

It appears from the code that the 'if' branch can be taken even if the
tag decl is a union. Is this valid in the C++ grammar? That is, can
there be a "base clause" for unions in C++, and if so, what does that
mean?
      

it seems not to be allowed -- at least both gcc and clang reject it.
Clang does it in ActOnBaseSpecifier in Sema:

  // C++ [class.union]p1:
  // A union shall not be used as a base class.
  if (BaseType->isUnionType()) {
    Diag(BaseLoc, diag::err_union_as_base_class, SpecifierRange);
    return;
  }

That's odd - it seems like this should be diagnosed by the parser. Since I'm not very familiar with all the "challenges" of implementing C ++:-), I'll understand if this isn't convenient.
  
Doug can probably explain it better, but it's not the C++ grammar that disallows union inheriting, it's the "semantic rules".
Also, in general, as suggested by Chris here:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-June/002004.html
it's better for the Parser to be as "relaxed" as possible and defer error checking to Sema (where appropriate).

-Argiris

steve naroff wrote:

Hi,

I just noticed the following code fragment in ParseClassSpecifier:

// Parse the tag portion of this.
DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc,
Name,
                                   NameLoc, Attr);

// Parse the optional base clause (C++ only).
if (getLang().CPlusPlus && Tok.is(tok::colon)) {
  ParseBaseClause(TagDecl);
}

It appears from the code that the 'if' branch can be taken even if the
tag decl is a union. Is this valid in the C++ grammar? That is, can
there be a "base clause" for unions in C++, and if so, what does that
mean?

it seems not to be allowed -- at least both gcc and clang reject it.
Clang does it in ActOnBaseSpecifier in Sema:

// C++ [class.union]p1:
// A union shall not be used as a base class.
if (BaseType->isUnionType()) {
   Diag(BaseLoc, diag::err_union_as_base_class, SpecifierRange);
   return;
}

That's odd - it seems like this should be diagnosed by the parser. Since I'm not very familiar with all the "challenges" of implementing C ++:-), I'll understand if this isn't convenient.

Doug can probably explain it better, but it's not the C++ grammar that disallows union inheriting, it's the "semantic rules".
Also, in general, as suggested by Chris here:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-June/002004.html
it's better for the Parser to be as "relaxed" as possible and defer error checking to Sema (where appropriate).

Thanks for the reference. Chris did a great job explaining the tradeoffs.

The unfortunate side-effect of doing everything in Sema is it complicates writing new "Action" modules. This isn't really a big deal, since writing a new Action module is non-trivial anyway (for C). For example, ActOnDeclarator() does a ton of work to validate what the user actually typed.

At present, it appears we've standardized on supporting multiple applications using clangs AST's. As long as this continues to work well, the issue of writing other Action modules is probably academic.

snaroff