From 56ff146ec46d45fab56ff7a09ecc6b04664f7624 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Thu, 8 Nov 2007 23:49:49 +0000 Subject: [PATCH] First patch toward rewriting of method definitions. This is work in progress. llvm-svn: 43915 --- clang/Parse/ParseObjc.cpp | 21 +++--- clang/Parse/Parser.cpp | 29 ++++++- clang/Sema/Sema.h | 7 ++ clang/Sema/SemaDecl.cpp | 117 +++++++++++++++++++++++++++++ clang/Sema/SemaType.cpp | 36 +++++++++ clang/include/clang/Parse/Action.h | 8 ++ clang/include/clang/Parse/Parser.h | 5 +- 7 files changed, 208 insertions(+), 15 deletions(-) diff --git a/clang/Parse/ParseObjc.cpp b/clang/Parse/ParseObjc.cpp index a149b8611f67..1f38c23ad503 100644 --- a/clang/Parse/ParseObjc.cpp +++ b/clang/Parse/ParseObjc.cpp @@ -1146,38 +1146,37 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { /// objc-method-def: objc-method-proto ';'[opt] '{' body '}' /// -void Parser::ParseObjCInstanceMethodDefinition() { +Parser::DeclTy *Parser::ParseObjCInstanceMethodDefinition() { assert(Tok.is(tok::minus) && "Method definitions should start with '-'"); - + DeclTy *MDecl = ParseObjCMethodPrototype(ObjcImpDecl); // FIXME: @optional/@protocol?? - AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl)); + AllImplMethods.push_back(MDecl); // parse optional ';' if (Tok.is(tok::semi)) ConsumeToken(); if (Tok.isNot(tok::l_brace)) { Diag (Tok, diag::err_expected_lbrace); - return; + return 0; } - - StmtResult FnBody = ParseCompoundStatementBody(); + return ObjcParseFunctionDefinition(MDecl); } /// objc-method-def: objc-method-proto ';'[opt] '{' body '}' /// -void Parser::ParseObjCClassMethodDefinition() { +Parser::DeclTy *Parser::ParseObjCClassMethodDefinition() { assert(Tok.is(tok::plus) && "Class method definitions should start with '+'"); + DeclTy *MDecl = ParseObjCMethodPrototype(ObjcImpDecl); // FIXME: @optional/@protocol?? - AllImplMethods.push_back(ParseObjCMethodPrototype(ObjcImpDecl)); + AllImplMethods.push_back(MDecl); // parse optional ';' if (Tok.is(tok::semi)) ConsumeToken(); if (Tok.isNot(tok::l_brace)) { Diag (Tok, diag::err_expected_lbrace); - return; + return 0; } - - StmtResult FnBody = ParseCompoundStatementBody(); + return ObjcParseFunctionDefinition(MDecl); } Parser::ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { diff --git a/clang/Parse/Parser.cpp b/clang/Parse/Parser.cpp index a2ba86e9035c..59a077d21b71 100644 --- a/clang/Parse/Parser.cpp +++ b/clang/Parse/Parser.cpp @@ -331,7 +331,7 @@ Parser::DeclTy *Parser::ParseExternalDeclaration() { return ParseObjCAtDirectives(); case tok::minus: if (getLang().ObjC1) { - ParseObjCInstanceMethodDefinition(); + return ParseObjCInstanceMethodDefinition(); } else { Diag(Tok, diag::err_expected_external_declaration); ConsumeToken(); @@ -339,7 +339,7 @@ Parser::DeclTy *Parser::ParseExternalDeclaration() { return 0; case tok::plus: if (getLang().ObjC1) { - ParseObjCClassMethodDefinition(); + return ParseObjCClassMethodDefinition(); } else { Diag(Tok, diag::err_expected_external_declaration); ConsumeToken(); @@ -465,6 +465,31 @@ Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) { return ParseFunctionStatementBody(Res, BraceLoc, BraceLoc); } +Parser::DeclTy *Parser::ObjcParseFunctionDefinition(DeclTy *D) { + // We should have an opening brace now. + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_fn_body); + + // Skip over garbage, until we get to '{'. Don't eat the '{'. + SkipUntil(tok::l_brace, true, true); + + // If we didn't find the '{', bail out. + if (Tok.isNot(tok::l_brace)) + return 0; + } + + SourceLocation BraceLoc = Tok.getLocation(); + + // Enter a scope for the function body. + EnterScope(Scope::FnScope|Scope::DeclScope); + + // Tell the actions module that we have entered a function definition with the + // specified Declarator for the function. + DeclTy *Res = Actions.ObjcActOnStartOfFunctionDef(CurScope, D); + + return ParseFunctionStatementBody(Res, BraceLoc, BraceLoc); +} + /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides /// types for a function with a K&R-style identifier list for arguments. void Parser::ParseKNRParamDeclarations(Declarator &D) { diff --git a/clang/Sema/Sema.h b/clang/Sema/Sema.h index 2781b1674555..28cf9c7b1905 100644 --- a/clang/Sema/Sema.h +++ b/clang/Sema/Sema.h @@ -172,6 +172,9 @@ public: // QualType GetTypeForDeclarator(Declarator &D, Scope *S); + QualType ObjcGetTypeForDeclarator(DeclTy *D, Scope *S); + + virtual TypeResult ActOnTypeName(Scope *S, Declarator &D); virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D); @@ -181,10 +184,12 @@ private: // virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S) const; virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup); + virtual DeclTy *ObjcActOnDeclarator(Scope *S, DeclTy *D, DeclTy *LastInGroup); void AddInitializerToDecl(DeclTy *dcl, ExprTy *init); virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group); virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, Declarator &D); + virtual DeclTy *ObjcActOnStartOfFunctionDef(Scope *S, DeclTy *D); virtual DeclTy *ActOnFunctionDefBody(DeclTy *Decl, StmtTy *Body); /// Scope actions. @@ -226,6 +231,8 @@ private: /// More parsing and symbol table subroutines... ParmVarDecl *ParseParamDeclarator(DeclaratorChunk &FI, unsigned ArgNo, Scope *FnBodyScope); + ParmVarDecl *ObjcParseParamDeclarator(ParmVarDecl *param, Scope *FnBodyScope); + ScopedDecl *LookupScopedDecl(IdentifierInfo *II, unsigned NSI, SourceLocation IdLoc, Scope *S); ScopedDecl *LookupInterfaceDecl(IdentifierInfo *II); diff --git a/clang/Sema/SemaDecl.cpp b/clang/Sema/SemaDecl.cpp index 4892847e734e..4f7ffc335c3d 100644 --- a/clang/Sema/SemaDecl.cpp +++ b/clang/Sema/SemaDecl.cpp @@ -544,6 +544,42 @@ bool Sema::CheckInitializer(Expr *&Init, QualType &DeclType, bool isStatic) { return hadError; } +Sema::DeclTy * +Sema::ObjcActOnDeclarator(Scope *S, DeclTy *D, DeclTy *lastDecl) { + ObjcMethodDecl *MDecl = dyn_cast(static_cast(D)); + + ScopedDecl *LastDeclarator = dyn_cast_or_null((Decl *)lastDecl); + const char *name = MDecl->getSelector().getName().c_str(); + IdentifierInfo *II = &Context.Idents.get(name); + assert (II && "ObjcActOnDeclarator - selector name is missing"); + + // The scope passed in may not be a decl scope. Zip up the scope tree until + // we find one that is. + while ((S->getFlags() & Scope::DeclScope) == 0) + S = S->getParent(); + + ScopedDecl *New; + QualType R = ObjcGetTypeForDeclarator(MDecl, S); + assert(!R.isNull() && "ObjcGetTypeForDeclarator() returned null type"); + + FunctionDecl *NewFD = new FunctionDecl(MDecl->getLocation(), II, R, + FunctionDecl::Static, + false, LastDeclarator); + New = NewFD; + + // If this has an identifier, add it to the scope stack. + if (II) { + New->setNext(II->getFETokenInfo()); + II->setFETokenInfo(New); + S->AddDecl(New); + } + + if (S->getParent() == 0) + AddTopLevelDecl(New, LastDeclarator); + + return New; +} + Sema::DeclTy * Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { ScopedDecl *LastDeclarator = dyn_cast_or_null((Decl *)lastDecl); @@ -853,7 +889,64 @@ Sema::ParseParamDeclarator(DeclaratorChunk &FTI, unsigned ArgNo, return New; } + +// Called from Sema::ObjcParseStartOfFunctionDef(). +ParmVarDecl * +Sema::ObjcParseParamDeclarator(ParmVarDecl *PI, Scope *FnScope) { + IdentifierInfo *II = PI->getIdentifier(); + // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. + // Can this happen for params? We already checked that they don't conflict + // among each other. Here they can only shadow globals, which is ok. + if (/*Decl *PrevDecl = */LookupScopedDecl(II, Decl::IDNS_Ordinary, + PI->getLocation(), FnScope)) { + + } + + // FIXME: Handle storage class (auto, register). No declarator? + // TODO: Chain to previous parameter with the prevdeclarator chain? + + // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). + // Doing the promotion here has a win and a loss. The win is the type for + // both Decl's and DeclRefExpr's will match (a convenient invariant for the + // code generator). The loss is the orginal type isn't preserved. For example: + // + // void func(int parmvardecl[5]) { // convert "int [5]" to "int *" + // int blockvardecl[5]; + // sizeof(parmvardecl); // size == 4 + // sizeof(blockvardecl); // size == 20 + // } + // + // For expressions, all implicit conversions are captured using the + // ImplicitCastExpr AST node (we have no such mechanism for Decl's). + // + // FIXME: If a source translation tool needs to see the original type, then + // we need to consider storing both types (in ParmVarDecl)... + // + QualType parmDeclType = PI->getType(); + if (const ArrayType *AT = parmDeclType->getAsArrayType()) + parmDeclType = Context.getPointerType(AT->getElementType()); + else if (parmDeclType->isFunctionType()) + parmDeclType = Context.getPointerType(parmDeclType); + + ParmVarDecl *New = new ParmVarDecl(PI->getLocation(), II, parmDeclType, + VarDecl::None, 0); + // FIXME: need to check for invalid type. + /** + if (PI.InvalidType) + New->setInvalidDecl(); + */ + + // If this has an identifier, add it to the scope stack. + if (II) { + New->setNext(II->getFETokenInfo()); + II->setFETokenInfo(New); + FnScope->AddDecl(New); + } + + return New; +} + Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { assert(CurFunctionDecl == 0 && "Function parsing confused"); @@ -938,6 +1031,30 @@ Sema::DeclTy *Sema::ActOnFunctionDefBody(DeclTy *D, StmtTy *Body) { return FD; } +Sema::DeclTy *Sema::ObjcActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) { + assert(CurFunctionDecl == 0 && "Function parsing confused"); + ObjcMethodDecl *MDecl = dyn_cast(static_cast(D)); + + assert(MDecl != 0 && "Not a method declarator!"); + + Scope *GlobalScope = FnBodyScope->getParent(); + + FunctionDecl *FD = + static_cast(ObjcActOnDeclarator(GlobalScope, D, 0)); + CurFunctionDecl = FD; + + // Create Decl objects for each parameter, adding them to the FunctionDecl. + llvm::SmallVector Params; + + for (int i = 0; i < MDecl->getNumParams(); i++) { + ParmVarDecl *PDecl = MDecl->getParamDecl(i); + Params.push_back(ObjcParseParamDeclarator(PDecl, FnBodyScope)); + } + + FD->setParams(&Params[0], Params.size()); + + return FD; +} /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). diff --git a/clang/Sema/SemaType.cpp b/clang/Sema/SemaType.cpp index abf132bf322c..8c18a2f27b50 100644 --- a/clang/Sema/SemaType.cpp +++ b/clang/Sema/SemaType.cpp @@ -325,6 +325,42 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { return T; } +/// GetTypeForDeclarator - Convert the type for the specified declarator to Type +/// instances. +QualType Sema::ObjcGetTypeForDeclarator(DeclTy *D, Scope *S) { + ObjcMethodDecl *MDecl = dyn_cast(static_cast(D)); + QualType T = MDecl->getResultType(); + llvm::SmallVector ArgTys; + + for (int i = 0; i < MDecl->getNumParams(); i++) { + ParmVarDecl *PDecl = MDecl->getParamDecl(i); + QualType ArgTy = PDecl->getType(); + assert(!ArgTy.isNull() && "Couldn't parse type?"); + // + // Perform the default function/array conversion (C99 6.7.5.3p[7,8]). + // This matches the conversion that is done in + // Sema::ParseParamDeclarator(). Without this conversion, the + // argument type in the function prototype *will not* match the + // type in ParmVarDecl (which makes the code generator unhappy). + // + // FIXME: We still apparently need the conversion in + // Sema::ParseParamDeclarator(). This doesn't make any sense, since + // it should be driving off the type being created here. + // + // FIXME: If a source translation tool needs to see the original type, + // then we need to consider storing both types somewhere... + // + if (const ArrayType *AT = ArgTy->getAsArrayType()) + ArgTy = Context.getPointerType(AT->getElementType()); + else if (ArgTy->isFunctionType()) + ArgTy = Context.getPointerType(ArgTy); + ArgTys.push_back(ArgTy); + } + T = Context.getFunctionType(T, &ArgTys[0], ArgTys.size(), + false); + return T; +} + Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // C99 6.7.6: Type names have no identifier. This is already validated by // the parser. diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index acdd27e1b7c0..34a1a3320d10 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -107,6 +107,9 @@ public: return 0; } + virtual DeclTy *ObjcActOnDeclarator(Scope *S, DeclTy *D,DeclTy *LastInGroup) { + return 0; + } /// AddInitializerToDecl - This action is called immediately after /// ParseDeclarator (when an initializer is present). The code is factored /// this way to make sure we are able to handle the following: @@ -131,6 +134,11 @@ public: return ActOnDeclarator(FnBodyScope, D, 0); } + virtual DeclTy *ObjcActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) { + // Default to ActOnDeclarator. + return ObjcActOnDeclarator(FnBodyScope, D, 0); + } + /// ActOnFunctionDefBody - This is called when a function body has completed /// parsing. Decl is the DeclTy returned by ParseStartOfFunctionDef. virtual DeclTy *ActOnFunctionDefBody(DeclTy *Decl, StmtTy *Body) { diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 7339d6ca5041..202a7f0c624e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -250,6 +250,7 @@ private: DeclTy *ParseExternalDeclaration(); DeclTy *ParseDeclarationOrFunctionDefinition(); DeclTy *ParseFunctionDefinition(Declarator &D); + DeclTy *ObjcParseFunctionDefinition(DeclTy *D); void ParseKNRParamDeclarations(Declarator &D); void ParseSimpleAsm(); void ParseAsmStringLiteral(); @@ -300,8 +301,8 @@ private: void ParseObjCPropertyAttribute(ObjcDeclSpec &DS); DeclTy *ParseObjCPropertyDecl(DeclTy *interfaceDecl, SourceLocation AtLoc); - void ParseObjCInstanceMethodDefinition(); - void ParseObjCClassMethodDefinition(); + DeclTy *ParseObjCInstanceMethodDefinition(); + DeclTy *ParseObjCClassMethodDefinition(); //===--------------------------------------------------------------------===// // C99 6.5: Expressions.