forked from OSchip/llvm-project
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:
parent
d9d2fb1420
commit
776fac8703
|
@ -124,9 +124,11 @@ void StmtPrinter::VisitNullStmt(NullStmt *Node) {
|
|||
}
|
||||
|
||||
void StmtPrinter::VisitDeclStmt(DeclStmt *Node) {
|
||||
Indent();
|
||||
PrintRawDecl(Node->getDecl());
|
||||
OS << ";\n";
|
||||
for (Decl *D = Node->getDecl(); D; D = D->getNextDeclarator()) {
|
||||
Indent();
|
||||
PrintRawDecl(D);
|
||||
OS << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) {
|
||||
|
|
|
@ -279,15 +279,15 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
|
|||
|
||||
if (Tok.getKind() == tok::semi) {
|
||||
ConsumeToken();
|
||||
return 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;
|
||||
return Actions.FinalizeDeclaratorGroup(CurScope, LastDeclInGroup);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -98,6 +98,8 @@ private:
|
|||
virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const;
|
||||
virtual DeclTy *ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
|
||||
DeclTy *LastInGroup);
|
||||
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
|
||||
|
||||
virtual DeclTy *ParseStartOfFunctionDef(Scope *S, Declarator &D);
|
||||
virtual DeclTy *ParseFunctionDefBody(DeclTy *Decl, StmtTy *Body);
|
||||
virtual void PopScope(SourceLocation Loc, Scope *S);
|
||||
|
@ -120,7 +122,7 @@ private:
|
|||
DeclTy **Elements, unsigned NumElements);
|
||||
private:
|
||||
/// Subroutines of ParseDeclarator()...
|
||||
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D);
|
||||
TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, Decl *LastDeclarator);
|
||||
TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
|
||||
FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old);
|
||||
VarDecl *MergeVarDecl(VarDecl *New, Decl *Old);
|
||||
|
|
|
@ -155,7 +155,8 @@ Decl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, Scope *S) {
|
|||
Builtin::ID BID = (Builtin::ID)bid;
|
||||
|
||||
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.
|
||||
while (S->getParent())
|
||||
|
@ -270,20 +271,21 @@ Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
Action::DeclTy *
|
||||
Sema::DeclTy *
|
||||
Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
|
||||
DeclTy *LastInGroup) {
|
||||
DeclTy *lastDeclarator) {
|
||||
Decl *LastDeclarator = (Decl*)lastDeclarator;
|
||||
IdentifierInfo *II = D.getIdentifier();
|
||||
|
||||
// See if this is a redefinition of a variable in the same scope.
|
||||
Decl *PrevDecl = LookupScopedDecl(II, Decl::IDNS_Ordinary,
|
||||
D.getIdentifierLoc(), S);
|
||||
if (!S->isDeclScope(PrevDecl))
|
||||
if (PrevDecl && !S->isDeclScope(PrevDecl))
|
||||
PrevDecl = 0; // If in outer scope, it isn't the same thing.
|
||||
|
||||
Decl *New;
|
||||
if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||
TypedefDecl *NewTD = ParseTypedefDecl(S, D);
|
||||
TypedefDecl *NewTD = ParseTypedefDecl(S, D, LastDeclarator);
|
||||
if (!NewTD) return 0;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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.
|
||||
if (PrevDecl) {
|
||||
|
@ -368,7 +371,7 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
|
|||
if (VerifyConstantArrayType(ary, D.getIdentifierLoc()))
|
||||
return 0;
|
||||
}
|
||||
NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC);
|
||||
NewVD = new FileVarDecl(D.getIdentifierLoc(), II, R, SC, LastDeclarator);
|
||||
} else {
|
||||
// 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...
|
||||
|
@ -387,7 +390,7 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
|
|||
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.
|
||||
if (PrevDecl) {
|
||||
|
@ -406,11 +409,27 @@ Sema::ParseDeclarator(Scope *S, Declarator &D, ExprTy *Init,
|
|||
}
|
||||
|
||||
if (S->getParent() == 0)
|
||||
AddTopLevelDecl(New, (Decl *)LastInGroup);
|
||||
AddTopLevelDecl(New, LastDeclarator);
|
||||
|
||||
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 *
|
||||
Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo,
|
||||
Scope *FnScope) {
|
||||
|
@ -426,9 +445,10 @@ Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo,
|
|||
}
|
||||
|
||||
// FIXME: Handle storage class (auto, register). No declarator?
|
||||
// TODO: Chain to previous parameter with the prevdeclarator chain?
|
||||
VarDecl *New = new ParmVarDecl(PI.IdentLoc, II,
|
||||
QualType::getFromOpaquePtr(PI.TypeInfo),
|
||||
VarDecl::None);
|
||||
VarDecl::None, 0);
|
||||
|
||||
// If this has an identifier, add it to the scope stack.
|
||||
if (II) {
|
||||
|
@ -556,14 +576,16 @@ Decl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
|
|||
}
|
||||
|
||||
|
||||
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D) {
|
||||
assert(D.getIdentifier() && "Wrong callback for declspec withotu declarator");
|
||||
TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D,
|
||||
Decl *LastDeclarator) {
|
||||
assert(D.getIdentifier() && "Wrong callback for declspec without declarator");
|
||||
|
||||
QualType T = GetTypeForDeclarator(D, S);
|
||||
if (T.isNull()) return 0;
|
||||
|
||||
// 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) {
|
||||
default: assert(0 && "Unknown tag kind!");
|
||||
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 (TK != TK_Definition) Diag(Loc, diag::ext_forward_ref_enum);
|
||||
break;
|
||||
case Decl::Union:
|
||||
case Decl::Struct:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -697,7 +723,9 @@ Sema::DeclTy *Sema::ParseField(Scope *S, DeclTy *TagDecl,
|
|||
if (VerifyConstantArrayType(ary, Loc))
|
||||
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,
|
||||
|
@ -837,7 +865,8 @@ Sema::DeclTy *Sema::ParseEnumConstant(Scope *S, DeclTy *EnumDeclX,
|
|||
return 0;
|
||||
}
|
||||
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.
|
||||
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;)
|
||||
// remember this in the LastInGroupList list.
|
||||
if (last) {
|
||||
if (last)
|
||||
LastInGroupList.push_back((Decl*)last);
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseAttribute GCC __attribute__
|
||||
|
|
|
@ -64,9 +64,13 @@ private:
|
|||
///
|
||||
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:
|
||||
Decl(Kind DK, SourceLocation L, IdentifierInfo *Id)
|
||||
: DeclKind(DK), Loc(L), Identifier(Id), Next(0) {
|
||||
Decl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *NextDecl)
|
||||
: DeclKind(DK), Loc(L), Identifier(Id), Next(0), NextDeclarator(NextDecl) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
virtual ~Decl();
|
||||
|
@ -81,6 +85,13 @@ public:
|
|||
Decl *getNext() const { return Next; }
|
||||
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 {
|
||||
switch (DeclKind) {
|
||||
default: assert(0 && "Unknown decl kind!");
|
||||
|
@ -113,8 +124,8 @@ public:
|
|||
class ValueDecl : public Decl {
|
||||
QualType DeclType;
|
||||
protected:
|
||||
ValueDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T):
|
||||
Decl(DK, L, Id), DeclType(T) {}
|
||||
ValueDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
Decl *PrevDecl) : Decl(DK, L, Id, PrevDecl), DeclType(T) {}
|
||||
public:
|
||||
QualType getType() const { return DeclType; }
|
||||
QualType getCanonicalType() const { return DeclType.getCanonicalType(); }
|
||||
|
@ -142,8 +153,8 @@ public:
|
|||
static bool classof(const VarDecl *D) { return true; }
|
||||
protected:
|
||||
VarDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
StorageClass SC)
|
||||
: ValueDecl(DK, L, Id, T) { SClass = SC; }
|
||||
StorageClass SC, Decl *PrevDecl)
|
||||
: ValueDecl(DK, L, Id, T, PrevDecl) { SClass = SC; }
|
||||
private:
|
||||
StorageClass SClass;
|
||||
// TODO: Initializer.
|
||||
|
@ -152,8 +163,9 @@ private:
|
|||
/// BlockVarDecl - Represent a local variable declaration.
|
||||
class BlockVarDecl : public VarDecl {
|
||||
public:
|
||||
BlockVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S)
|
||||
: VarDecl(BlockVariable, L, Id, T, S) {}
|
||||
BlockVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
|
||||
Decl *PrevDecl)
|
||||
: VarDecl(BlockVariable, L, Id, T, S, PrevDecl) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == BlockVariable; }
|
||||
|
@ -166,8 +178,9 @@ public:
|
|||
/// pointer to the decl's scope, which is transient).
|
||||
class FileVarDecl : public VarDecl {
|
||||
public:
|
||||
FileVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S)
|
||||
: VarDecl(FileVariable, L, Id, T, S) {}
|
||||
FileVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
|
||||
Decl *PrevDecl)
|
||||
: VarDecl(FileVariable, L, Id, T, S, PrevDecl) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == FileVariable; }
|
||||
|
@ -177,8 +190,9 @@ public:
|
|||
/// ParmVarDecl - Represent a parameter to a function.
|
||||
class ParmVarDecl : public VarDecl {
|
||||
public:
|
||||
ParmVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S)
|
||||
: VarDecl(ParmVariable, L, Id, T, S) {}
|
||||
ParmVarDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S,
|
||||
Decl *PrevDecl)
|
||||
: VarDecl(ParmVariable, L, Id, T, S, PrevDecl) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == ParmVariable; }
|
||||
|
@ -192,8 +206,9 @@ public:
|
|||
enum StorageClass {
|
||||
None, Extern, Static
|
||||
};
|
||||
FunctionDecl(SourceLocation L, IdentifierInfo *Id, QualType T, StorageClass S=None)
|
||||
: ValueDecl(Function, L, Id, T),
|
||||
FunctionDecl(SourceLocation L, IdentifierInfo *Id, QualType T,
|
||||
StorageClass S = None, Decl *PrevDecl)
|
||||
: ValueDecl(Function, L, Id, T, PrevDecl),
|
||||
ParamInfo(0), Body(0), DeclChain(0), SClass(S) {}
|
||||
virtual ~FunctionDecl();
|
||||
|
||||
|
@ -240,8 +255,8 @@ private:
|
|||
class FieldDecl : public Decl {
|
||||
QualType DeclType;
|
||||
public:
|
||||
FieldDecl(SourceLocation L, IdentifierInfo *Id, QualType T)
|
||||
: Decl(Field, L, Id), DeclType(T) {}
|
||||
FieldDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Decl *PrevDecl)
|
||||
: Decl(Field, L, Id, PrevDecl), DeclType(T) {}
|
||||
|
||||
QualType getType() const { return DeclType; }
|
||||
QualType getCanonicalType() const { return DeclType.getCanonicalType(); }
|
||||
|
@ -260,8 +275,9 @@ public:
|
|||
class EnumConstantDecl : public ValueDecl {
|
||||
Expr *Init; // an integer constant expression
|
||||
public:
|
||||
EnumConstantDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E)
|
||||
: ValueDecl(EnumConstant, L, Id, T), Init(E) {}
|
||||
EnumConstantDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Expr *E,
|
||||
Decl *PrevDecl)
|
||||
: ValueDecl(EnumConstant, L, Id, T, PrevDecl), Init(E) {}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) {
|
||||
|
@ -280,8 +296,8 @@ class TypeDecl : public Decl {
|
|||
Type *TypeForDecl;
|
||||
friend class ASTContext;
|
||||
protected:
|
||||
TypeDecl(Kind DK, SourceLocation L, IdentifierInfo *Id)
|
||||
: Decl(DK, L, Id), TypeForDecl(0) {}
|
||||
TypeDecl(Kind DK, SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
|
||||
: Decl(DK, L, Id, PrevDecl), TypeForDecl(0) {}
|
||||
public:
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
@ -296,8 +312,8 @@ class TypedefDecl : public TypeDecl {
|
|||
/// UnderlyingType - This is the type the typedef is set to.
|
||||
QualType UnderlyingType;
|
||||
public:
|
||||
TypedefDecl(SourceLocation L, IdentifierInfo *Id, QualType T)
|
||||
: TypeDecl(Typedef, L, Id), UnderlyingType(T) {}
|
||||
TypedefDecl(SourceLocation L, IdentifierInfo *Id, QualType T, Decl *PrevDecl)
|
||||
: TypeDecl(Typedef, L, Id, PrevDecl), UnderlyingType(T) {}
|
||||
|
||||
QualType getUnderlyingType() const { return UnderlyingType; }
|
||||
|
||||
|
@ -313,7 +329,8 @@ class TagDecl : public TypeDecl {
|
|||
/// it is a declaration ("struct foo;").
|
||||
bool IsDefinition : 1;
|
||||
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;
|
||||
}
|
||||
public:
|
||||
|
@ -351,7 +368,8 @@ class EnumDecl : public TagDecl {
|
|||
EnumConstantDecl **Elements; // Null if not defined.
|
||||
int NumElements; // -1 if not defined.
|
||||
public:
|
||||
EnumDecl(SourceLocation L, IdentifierInfo *Id) : TagDecl(Enum, L, Id) {
|
||||
EnumDecl(SourceLocation L, IdentifierInfo *Id, Decl *PrevDecl)
|
||||
: TagDecl(Enum, L, Id, PrevDecl) {
|
||||
Elements = 0;
|
||||
NumElements = -1;
|
||||
}
|
||||
|
@ -379,7 +397,8 @@ class RecordDecl : public TagDecl {
|
|||
FieldDecl **Members; // Null if not defined.
|
||||
int NumMembers; // -1 if not defined.
|
||||
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;
|
||||
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
|
||||
Members = 0;
|
||||
|
|
|
@ -98,6 +98,12 @@ public:
|
|||
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
|
||||
/// definition, instead of calling ParseDeclarator. The Declarator includes
|
||||
/// information about formal arguments that are part of this function.
|
||||
|
|
Loading…
Reference in New Issue