Finally break down and chain together decls that are defined with common declspecs,

like: int X, Y, Z;

This is required for the code gen to get to all of the declarations in a
DeclStmt, and should simplify some other code.

llvm-svn: 39623
This commit is contained in:
Chris Lattner 2007-06-09 00:53:06 +00:00
parent d9d2fb1420
commit 776fac8703
6 changed files with 113 additions and 56 deletions

View File

@ -124,9 +124,11 @@ void StmtPrinter::VisitNullStmt(NullStmt *Node) {
} }
void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
Indent(); for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
PrintRawDecl(Node->getDecl()); Indent();
OS << ";\n"; PrintRawDecl(D);
OS << ";\n";
}
} }
void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) { void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {

View File

@ -279,15 +279,15 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
if (Tok.getKind() == tok::semi) { if (Tok.getKind() == tok::semi) {
ConsumeToken(); ConsumeToken();
return LastDeclInGroup; return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
} else {
Diag(Tok, diag::err_parse_error);
// Skip to end of block or statement
SkipUntil(tok::r_brace, true);
if (Tok.getKind() == tok::semi)
ConsumeToken();
return 0;
} }
Diag(Tok, diag::err_parse_error);
// Skip to end of block or statement
SkipUntil(tok::r_brace, true);
if (Tok.getKind() == tok::semi)
ConsumeToken();
return 0;
} }
/// ParseSpecifierQualifierList /// ParseSpecifierQualifierList

View File

@ -98,6 +98,8 @@ private:
virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const; virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const;
virtual DeclTy *ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init, virtual DeclTy *ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
DeclTy *LastInGroup); DeclTy *LastInGroup);
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
virtual DeclTy *ParseStartOfFunctionDef(Scope *S, Declarator &D); virtual DeclTy *ParseStartOfFunctionDef(Scope *S, Declarator &D);
virtual DeclTy *ParseFunctionDefBody(DeclTy *Decl, StmtTy *Body); virtual DeclTy *ParseFunctionDefBody(DeclTy *Decl, StmtTy *Body);
virtual void PopScope(SourceLocation Loc, Scope *S); virtual void PopScope(SourceLocation Loc, Scope *S);
@ -120,7 +122,7 @@ private:
DeclTy **Elements, unsigned NumElements); DeclTy **Elements, unsigned NumElements);
private: private:
/// Subroutines of ParseDeclarator()... /// Subroutines of ParseDeclarator()...
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D); TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, Decl *LastDeclarator);
TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old); TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old); FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old);
VarDecl *MergeVarDecl(VarDecl *New, Decl *Old); VarDecl *MergeVarDecl(VarDecl *New, Decl *Old);

View File

@ -155,7 +155,8 @@ Decl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, Scope *S) {
Builtin::ID BID = (Builtin::ID)bid; Builtin::ID BID = (Builtin::ID)bid;
QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context); QualType R = Context.BuiltinInfo.GetBuiltinType(BID, Context);
FunctionDecl *New = new FunctionDecl(SourceLocation(), II, R); FunctionDecl *New = new FunctionDecl(SourceLocation(), II, R,
FunctionDecl::Extern, 0);
// Find translation-unit scope to insert this function into. // Find translation-unit scope to insert this function into.
while (S->getParent()) while (S->getParent())
@ -270,20 +271,21 @@ Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
return 0; return 0;
} }
Action::DeclTy * Sema::DeclTy *
Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init, Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
DeclTy *LastInGroup) { DeclTy *lastDeclarator) {
Decl *LastDeclarator = (Decl*)lastDeclarator;
IdentifierInfo *II = D.getIdentifier(); IdentifierInfo *II = D.getIdentifier();
// See if this is a redefinition of a variable in the same scope. // See if this is a redefinition of a variable in the same scope.
Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary, Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary,
D.getIdentifierLoc(), S); D.getIdentifierLoc(), S);
if (!S->isDeclScope(PrevDecl)) if (PrevDecl && !S->isDeclScope(PrevDecl))
PrevDecl = 0; // If in outer scope, it isn't the same thing. PrevDecl = 0; // If in outer scope, it isn't the same thing.
Decl *New; Decl *New;
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
TypedefDecl *NewTD = ParseTypedefDecl(S, D); TypedefDecl *NewTD = ParseTypedefDecl(S, D, LastDeclarator);
if (!NewTD) return 0; if (!NewTD) return 0;
// Merge the decl with the existing one if appropriate. // Merge the decl with the existing one if appropriate.
@ -317,7 +319,8 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
case DeclSpec::SCS_static: SC = FunctionDecl::Static; break; case DeclSpec::SCS_static: SC = FunctionDecl::Static; break;
} }
FunctionDecl *NewFD = new FunctionDecl(D.getIdentifierLoc(), II, R, SC); FunctionDecl *NewFD = new FunctionDecl(D.getIdentifierLoc(), II, R, SC,
LastDeclarator);
// Merge the decl with the existing one if appropriate. // Merge the decl with the existing one if appropriate.
if (PrevDecl) { if (PrevDecl) {
@ -368,7 +371,7 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
if (VerifyConstantArrayType(ary, D.getIdentifierLoc())) if (VerifyConstantArrayType(ary, D.getIdentifierLoc()))
return 0; return 0;
} }
NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC); NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator);
} else { } else {
// Block scope. C99 6.7p7: If an identifier for an object is declared with // Block scope. C99 6.7p7: If an identifier for an object is declared with
// no linkage (C99 6.2.2p6), the type for the object shall be complete... // no linkage (C99 6.2.2p6), the type for the object shall be complete...
@ -387,7 +390,7 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
return 0; return 0;
} }
} }
NewVD = new BlockVarDecl(D.getIdentifierLoc(), II, R, SC); NewVD = new BlockVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator);
} }
// Merge the decl with the existing one if appropriate. // Merge the decl with the existing one if appropriate.
if (PrevDecl) { if (PrevDecl) {
@ -406,11 +409,27 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
} }
if (S->getParent() == 0) if (S->getParent() == 0)
AddTopLevelDecl(New, (Decl *)LastInGroup); AddTopLevelDecl(New, LastDeclarator);
return New; return New;
} }
/// The declarators are chained together backwards, reverse the list.
Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) {
// Often we have single declarators, handle them quickly.
Decl *Group = static_cast<Decl*>(group);
if (Group->getNextDeclarator() == 0) return Group;
Decl *NewGroup = 0;
while (Group) {
Decl *Next = Group->getNextDeclarator();
Group->setNextDeclarator(NewGroup);
NewGroup = Group;
Group = Next;
}
return NewGroup;
}
VarDecl * VarDecl *
Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo, Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo,
Scope *FnScope) { Scope *FnScope) {
@ -426,9 +445,10 @@ Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo,
} }
// FIXME: Handle storage class (auto, register). No declarator? // FIXME: Handle storage class (auto, register). No declarator?
// TODO: Chain to previous parameter with the prevdeclarator chain?
VarDecl *New = new ParmVarDecl(PI.IdentLoc, II, VarDecl *New = new ParmVarDecl(PI.IdentLoc, II,
QualType::getFromOpaquePtr(PI.TypeInfo), QualType::getFromOpaquePtr(PI.TypeInfo),
VarDecl::None); VarDecl::None, 0);
// If this has an identifier, add it to the scope stack. // If this has an identifier, add it to the scope stack.
if (II) { if (II) {
@ -556,14 +576,16 @@ Decl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
} }
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D) { TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D,
assert(D.getIdentifier() && "Wrong callback for declspec withotu declarator"); Decl *LastDeclarator) {
assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
QualType T = GetTypeForDeclarator(D, S); QualType T = GetTypeForDeclarator(D, S);
if (T.isNull()) return 0; if (T.isNull()) return 0;
// Scope manipulation handled by caller. // Scope manipulation handled by caller.
return new TypedefDecl(D.getIdentifierLoc(), D.getIdentifier(), T); return new TypedefDecl(D.getIdentifierLoc(), D.getIdentifier(), T,
LastDeclarator);
} }
@ -638,14 +660,18 @@ Sema::DeclTy *Sema::ParseTag(Scope *S, unsigned TagType, TagKind TK,
switch (Kind) { switch (Kind) {
default: assert(0 && "Unknown tag kind!"); default: assert(0 && "Unknown tag kind!");
case Decl::Enum: case Decl::Enum:
New = new EnumDecl(Loc, Name); // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// enum X { A, B, C } D; D should chain to X.
New = new EnumDecl(Loc, Name, 0);
// If this is an undefined enum, warn. // If this is an undefined enum, warn.
if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum); if (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum);
break; break;
case Decl::Union: case Decl::Union:
case Decl::Struct: case Decl::Struct:
case Decl::Class: case Decl::Class:
New = new RecordDecl(Kind, Loc, Name); // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.:
// struct X { int A; } D; D should chain to X.
New = new RecordDecl(Kind, Loc, Name, 0);
break; break;
} }
@ -697,7 +723,9 @@ Sema::DeclTy *Sema::ParseField(Scope *S, DeclTy *TagDecl,
if (VerifyConstantArrayType(ary, Loc)) if (VerifyConstantArrayType(ary, Loc))
return 0; return 0;
} }
return new FieldDecl(Loc, II, T);
// FIXME: Chain fielddecls together.
return new FieldDecl(Loc, II, T, 0);
} }
void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl, void Sema::ParseRecordBody(SourceLocation RecLoc, DeclTy *RecDecl,
@ -837,7 +865,8 @@ Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *EnumDeclX,
return 0; return 0;
} }
QualType Ty = Context.getTagDeclType(TheEnumDecl); QualType Ty = Context.getTagDeclType(TheEnumDecl);
EnumConstantDecl *New = new EnumConstantDecl(IdLoc, Id, Ty, (Expr *)Val); // FIXME: Chain EnumConstantDecl's together.
EnumConstantDecl *New = new EnumConstantDecl(IdLoc, Id, Ty, (Expr *)Val, 0);
// Register this decl in the current scope stack. // Register this decl in the current scope stack.
New->setNext(Id->getFETokenInfo<Decl>()); New->setNext(Id->getFETokenInfo<Decl>());
@ -869,9 +898,8 @@ void Sema::AddTopLevelDecl(Decl *current, Decl *last) {
// If this is a top-level decl that is chained to some other (e.g. int A,B,C;) // If this is a top-level decl that is chained to some other (e.g. int A,B,C;)
// remember this in the LastInGroupList list. // remember this in the LastInGroupList list.
if (last) { if (last)
LastInGroupList.push_back((Decl*)last); LastInGroupList.push_back((Decl*)last);
}
} }
/// ParseAttribute GCC __attribute__ /// ParseAttribute GCC __attribute__

View File

@ -64,9 +64,13 @@ private:
/// ///
Decl *Next; Decl *Next;
/// NextDeclarator - If this decl was part of a multi-declarator declaration,
/// such as "int X, Y, *Z;" this indicates Decl for the next declarator.
Decl *NextDeclarator;
protected: protected:
Decl(Kind DK, SourceLocation L, IdentifierInfo *Id) Decl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *NextDecl)
: DeclKind(DK), Loc(L), Identifier(Id), Next(0) { : DeclKind(DK), Loc(L), Identifier(Id), Next(0), NextDeclarator(NextDecl) {
if (Decl::CollectingStats()) addDeclKind(DK); if (Decl::CollectingStats()) addDeclKind(DK);
} }
virtual ~Decl(); virtual ~Decl();
@ -81,6 +85,13 @@ public:
Decl *getNext() const { return Next; } Decl *getNext() const { return Next; }
void setNext(Decl *N) { Next = N; } void setNext(Decl *N) { Next = N; }
/// getNextDeclarator - If this decl was part of a multi-declarator
/// declaration, such as "int X, Y, *Z;" this returns the decl for the next
/// declarator. Otherwise it returns null.
Decl *getNextDeclarator() { return NextDeclarator; }
const Decl *getNextDeclarator() const { return NextDeclarator; }
void setNextDeclarator(Decl *N) { NextDeclarator = N; }
IdentifierNamespace getIdentifierNamespace() const { IdentifierNamespace getIdentifierNamespace() const {
switch (DeclKind) { switch (DeclKind) {
default: assert(0 && "Unknown decl kind!"); default: assert(0 && "Unknown decl kind!");
@ -113,8 +124,8 @@ public:
class ValueDecl : public Decl { class ValueDecl : public Decl {
QualType DeclType; QualType DeclType;
protected: protected:
ValueDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T): ValueDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
Decl(DK, L, Id), DeclType(T) {} Decl *PrevDecl) : Decl(DK, L, Id, PrevDecl), DeclType(T) {}
public: public:
QualType getType() const { return DeclType; } QualType getType() const { return DeclType; }
QualType getCanonicalType() const { return DeclType.getCanonicalType(); } QualType getCanonicalType() const { return DeclType.getCanonicalType(); }
@ -142,8 +153,8 @@ public:
static bool classof(const VarDecl *D) { return true; } static bool classof(const VarDecl *D) { return true; }
protected: protected:
VarDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T, VarDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
StorageClass SC) StorageClass SC, Decl *PrevDecl)
: ValueDecl(DK, L, Id, T) { SClass = SC; } : ValueDecl(DK, L, Id, T, PrevDecl) { SClass = SC; }
private: private:
StorageClass SClass; StorageClass SClass;
// TODO: Initializer. // TODO: Initializer.
@ -152,8 +163,9 @@ private:
/// BlockVarDecl - Represent a local variable declaration. /// BlockVarDecl - Represent a local variable declaration.
class BlockVarDecl : public VarDecl { class BlockVarDecl : public VarDecl {
public: public:
BlockVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S) BlockVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
: VarDecl(BlockVariable, L, Id, T, S) {} Decl *PrevDecl)
: VarDecl(BlockVariable, L, Id, T, S, PrevDecl) {}
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return D->getKind() == BlockVariable; } static bool classof(const Decl *D) { return D->getKind() == BlockVariable; }
@ -166,8 +178,9 @@ public:
/// pointer to the decl's scope, which is transient). /// pointer to the decl's scope, which is transient).
class FileVarDecl : public VarDecl { class FileVarDecl : public VarDecl {
public: public:
FileVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S) FileVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
: VarDecl(FileVariable, L, Id, T, S) {} Decl *PrevDecl)
: VarDecl(FileVariable, L, Id, T, S, PrevDecl) {}
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return D->getKind() == FileVariable; } static bool classof(const Decl *D) { return D->getKind() == FileVariable; }
@ -177,8 +190,9 @@ public:
/// ParmVarDecl - Represent a parameter to a function. /// ParmVarDecl - Represent a parameter to a function.
class ParmVarDecl : public VarDecl { class ParmVarDecl : public VarDecl {
public: public:
ParmVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S) ParmVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
: VarDecl(ParmVariable, L, Id, T, S) {} Decl *PrevDecl)
: VarDecl(ParmVariable, L, Id, T, S, PrevDecl) {}
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return D->getKind() == ParmVariable; } static bool classof(const Decl *D) { return D->getKind() == ParmVariable; }
@ -192,8 +206,9 @@ public:
enum StorageClass { enum StorageClass {
None, Extern, Static None, Extern, Static
}; };
FunctionDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S=None) FunctionDecl(SourceLocation L, IdentifierInfo *Id, QualType T,
: ValueDecl(Function, L, Id, T), StorageClass S = None, Decl *PrevDecl)
: ValueDecl(Function, L, Id, T, PrevDecl),
ParamInfo(0), Body(0), DeclChain(0), SClass(S) {} ParamInfo(0), Body(0), DeclChain(0), SClass(S) {}
virtual ~FunctionDecl(); virtual ~FunctionDecl();
@ -240,8 +255,8 @@ private:
class FieldDecl : public Decl { class FieldDecl : public Decl {
QualType DeclType; QualType DeclType;
public: public:
FieldDecl(SourceLocation L, IdentifierInfo *Id, QualType T) FieldDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Decl *PrevDecl)
: Decl(Field, L, Id), DeclType(T) {} : Decl(Field, L, Id, PrevDecl), DeclType(T) {}
QualType getType() const { return DeclType; } QualType getType() const { return DeclType; }
QualType getCanonicalType() const { return DeclType.getCanonicalType(); } QualType getCanonicalType() const { return DeclType.getCanonicalType(); }
@ -260,8 +275,9 @@ public:
class EnumConstantDecl : public ValueDecl { class EnumConstantDecl : public ValueDecl {
Expr *Init; // an integer constant expression Expr *Init; // an integer constant expression
public: public:
EnumConstantDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E) EnumConstantDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E,
: ValueDecl(EnumConstant, L, Id, T), Init(E) {} Decl *PrevDecl)
: ValueDecl(EnumConstant, L, Id, T, PrevDecl), Init(E) {}
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { static bool classof(const Decl *D) {
@ -280,8 +296,8 @@ class TypeDecl : public Decl {
Type *TypeForDecl; Type *TypeForDecl;
friend class ASTContext; friend class ASTContext;
protected: protected:
TypeDecl(Kind DK, SourceLocation L, IdentifierInfo *Id) TypeDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
: Decl(DK, L, Id), TypeForDecl(0) {} : Decl(DK, L, Id, PrevDecl), TypeForDecl(0) {}
public: public:
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
@ -296,8 +312,8 @@ class TypedefDecl : public TypeDecl {
/// UnderlyingType - This is the type the typedef is set to. /// UnderlyingType - This is the type the typedef is set to.
QualType UnderlyingType; QualType UnderlyingType;
public: public:
TypedefDecl(SourceLocation L, IdentifierInfo *Id, QualType T) TypedefDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Decl *PrevDecl)
: TypeDecl(Typedef, L, Id), UnderlyingType(T) {} : TypeDecl(Typedef, L, Id, PrevDecl), UnderlyingType(T) {}
QualType getUnderlyingType() const { return UnderlyingType; } QualType getUnderlyingType() const { return UnderlyingType; }
@ -313,7 +329,8 @@ class TagDecl : public TypeDecl {
/// it is a declaration ("struct foo;"). /// it is a declaration ("struct foo;").
bool IsDefinition : 1; bool IsDefinition : 1;
protected: protected:
TagDecl(Kind DK, SourceLocation L, IdentifierInfo *Id) : TypeDecl(DK, L, Id) { TagDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
: TypeDecl(DK, L, Id, PrevDecl) {
IsDefinition = false; IsDefinition = false;
} }
public: public:
@ -351,7 +368,8 @@ class EnumDecl : public TagDecl {
EnumConstantDecl **Elements; // Null if not defined. EnumConstantDecl **Elements; // Null if not defined.
int NumElements; // -1 if not defined. int NumElements; // -1 if not defined.
public: public:
EnumDecl(SourceLocation L, IdentifierInfo *Id) : TagDecl(Enum, L, Id) { EnumDecl(SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
: TagDecl(Enum, L, Id, PrevDecl) {
Elements = 0; Elements = 0;
NumElements = -1; NumElements = -1;
} }
@ -379,7 +397,8 @@ class RecordDecl : public TagDecl {
FieldDecl **Members; // Null if not defined. FieldDecl **Members; // Null if not defined.
int NumMembers; // -1 if not defined. int NumMembers; // -1 if not defined.
public: public:
RecordDecl(Kind DK, SourceLocation L, IdentifierInfo *Id) :TagDecl(DK, L, Id){ RecordDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
: TagDecl(DK, L, Id, PrevDecl) {
HasFlexibleArrayMember = false; HasFlexibleArrayMember = false;
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
Members = 0; Members = 0;

View File

@ -98,6 +98,12 @@ public:
return 0; return 0;
} }
/// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, this
/// gives the actions implementation a chance to process the group as a whole.
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group) {
return Group;
}
/// ParseStartOfFunctionDef - This is called at the start of a function /// ParseStartOfFunctionDef - This is called at the start of a function
/// definition, instead of calling ParseDeclarator. The Declarator includes /// definition, instead of calling ParseDeclarator. The Declarator includes
/// information about formal arguments that are part of this function. /// information about formal arguments that are part of this function.