зеркало из https://github.com/microsoft/clang-1.git
objective-c: just as we have done for method definitions,
c-functions declared in implementation should have their parsing delayed until the end so, they can access forward declared private methods. // rdar://10387088 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159626 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
a9e8b9e3e9
Коммит
6c89eafc90
|
@ -1019,7 +1019,7 @@ private:
|
|||
void ParseLexedMethodDef(LexedMethod &LM);
|
||||
void ParseLexedMemberInitializers(ParsingClass &Class);
|
||||
void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI);
|
||||
Decl *ParseLexedObjCMethodDefs(LexedMethod &LM);
|
||||
void ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod);
|
||||
bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks);
|
||||
bool ConsumeAndStoreUntil(tok::TokenKind T1,
|
||||
CachedTokens &Toks,
|
||||
|
@ -1084,11 +1084,12 @@ private:
|
|||
struct ObjCImplParsingDataRAII {
|
||||
Parser &P;
|
||||
Decl *Dcl;
|
||||
bool HasCFunction;
|
||||
typedef SmallVector<LexedMethod*, 8> LateParsedObjCMethodContainer;
|
||||
LateParsedObjCMethodContainer LateParsedObjCMethods;
|
||||
|
||||
ObjCImplParsingDataRAII(Parser &parser, Decl *D)
|
||||
: P(parser), Dcl(D) {
|
||||
: P(parser), Dcl(D), HasCFunction(false) {
|
||||
P.CurParsedObjCImpl = this;
|
||||
Finished = false;
|
||||
}
|
||||
|
@ -1101,6 +1102,7 @@ private:
|
|||
bool Finished;
|
||||
};
|
||||
ObjCImplParsingDataRAII *CurParsedObjCImpl;
|
||||
void StashAwayMethodOrFunctionBodyTokens(Decl *MDecl);
|
||||
|
||||
DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc);
|
||||
DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
|
||||
|
|
|
@ -1317,7 +1317,11 @@ public:
|
|||
void CheckForFunctionRedefinition(FunctionDecl *FD);
|
||||
Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
|
||||
Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D);
|
||||
void ActOnStartOfObjCMethodDef(Scope *S, Decl *D);
|
||||
void ActOnStartOfObjCMethodOrCFunctionDef(Scope *S, Decl *D,
|
||||
bool parseMethod);
|
||||
bool isObjCMethodDecl(Decl *D) {
|
||||
return D && isa<ObjCMethodDecl>(D);
|
||||
}
|
||||
|
||||
void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope);
|
||||
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
|
||||
|
|
|
@ -1379,6 +1379,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
|
|||
|
||||
bool ExpectSemi = Context != Declarator::ForContext;
|
||||
|
||||
if (CurParsedObjCImpl && D.isFunctionDeclarator() &&
|
||||
Tok.is(tok::l_brace)) {
|
||||
// Consume the tokens and store them for later parsing.
|
||||
StashAwayMethodOrFunctionBodyTokens(FirstDecl);
|
||||
CurParsedObjCImpl->HasCFunction = true;
|
||||
ExpectSemi = false;
|
||||
}
|
||||
|
||||
// If we don't have a comma, it is either the end of the list (a ';') or an
|
||||
// error, bail out.
|
||||
while (Tok.is(tok::comma)) {
|
||||
|
|
|
@ -1575,10 +1575,16 @@ void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) {
|
|||
assert(!Finished);
|
||||
P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl);
|
||||
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
|
||||
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i]);
|
||||
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
|
||||
true/*Methods*/);
|
||||
|
||||
P.Actions.ActOnAtEnd(P.getCurScope(), AtEnd);
|
||||
|
||||
if (HasCFunction)
|
||||
for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i)
|
||||
P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i],
|
||||
false/*c-functions*/);
|
||||
|
||||
/// \brief Clear and free the cached objc methods.
|
||||
for (LateParsedObjCMethodContainer::iterator
|
||||
I = LateParsedObjCMethods.begin(),
|
||||
|
@ -1915,6 +1921,19 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
|
|||
AutoreleasePoolBody.take());
|
||||
}
|
||||
|
||||
/// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them
|
||||
/// for later parsing.
|
||||
void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
|
||||
LexedMethod* LM = new LexedMethod(this, MDecl);
|
||||
CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
|
||||
CachedTokens &Toks = LM->Toks;
|
||||
// Begin by storing the '{' token.
|
||||
Toks.push_back(Tok);
|
||||
ConsumeBrace();
|
||||
// Consume everything up to (and including) the matching right brace.
|
||||
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
||||
}
|
||||
|
||||
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
|
||||
///
|
||||
Decl *Parser::ParseObjCMethodDefinition() {
|
||||
|
@ -1955,15 +1974,7 @@ Decl *Parser::ParseObjCMethodDefinition() {
|
|||
|
||||
if (CurParsedObjCImpl) {
|
||||
// Consume the tokens and store them for later parsing.
|
||||
LexedMethod* LM = new LexedMethod(this, MDecl);
|
||||
CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
|
||||
CachedTokens &Toks = LM->Toks;
|
||||
// Begin by storing the '{' token.
|
||||
Toks.push_back(Tok);
|
||||
ConsumeBrace();
|
||||
// Consume everything up to (and including) the matching right brace.
|
||||
ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
|
||||
|
||||
StashAwayMethodOrFunctionBodyTokens(MDecl);
|
||||
} else {
|
||||
ConsumeBrace();
|
||||
SkipUntil(tok::r_brace, /*StopAtSemi=*/false);
|
||||
|
@ -2821,8 +2832,15 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) {
|
|||
T.getCloseLocation()));
|
||||
}
|
||||
|
||||
Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
|
||||
|
||||
void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
|
||||
// MCDecl might be null due to error in method or c-function prototype, etc.
|
||||
Decl *MCDecl = LM.D;
|
||||
bool skip = MCDecl &&
|
||||
((parseMethod && !Actions.isObjCMethodDecl(MCDecl)) ||
|
||||
(!parseMethod && Actions.isObjCMethodDecl(MCDecl)));
|
||||
if (skip)
|
||||
return;
|
||||
|
||||
// Save the current token position.
|
||||
SourceLocation OrigLoc = Tok.getLocation();
|
||||
|
||||
|
@ -2832,24 +2850,25 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
|
|||
LM.Toks.push_back(Tok);
|
||||
PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
|
||||
|
||||
// MDecl might be null due to error in method prototype, etc.
|
||||
Decl *MDecl = LM.D;
|
||||
// Consume the previously pushed token.
|
||||
ConsumeAnyToken();
|
||||
|
||||
assert(Tok.is(tok::l_brace) && "Inline objective-c method not starting with '{'");
|
||||
SourceLocation BraceLoc = Tok.getLocation();
|
||||
// Enter a scope for the method body.
|
||||
// Enter a scope for the method or c-fucntion body.
|
||||
ParseScope BodyScope(this,
|
||||
Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope);
|
||||
parseMethod
|
||||
? Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope
|
||||
: Scope::FnScope|Scope::DeclScope);
|
||||
|
||||
// Tell the actions module that we have entered a method definition with the
|
||||
// specified Declarator for the method.
|
||||
Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
|
||||
// Tell the actions module that we have entered a method or c-function definition
|
||||
// with the specified Declarator for the method/function.
|
||||
Actions.ActOnStartOfObjCMethodOrCFunctionDef(getCurScope(), MCDecl, parseMethod);
|
||||
|
||||
if (SkipFunctionBodies && trySkippingFunctionBody()) {
|
||||
BodyScope.Exit();
|
||||
return Actions.ActOnFinishFunctionBody(MDecl, 0);
|
||||
(void)Actions.ActOnFinishFunctionBody(MCDecl, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
StmtResult FnBody(ParseCompoundStatementBody());
|
||||
|
@ -2864,7 +2883,7 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
|
|||
// Leave the function body scope.
|
||||
BodyScope.Exit();
|
||||
|
||||
MDecl = Actions.ActOnFinishFunctionBody(MDecl, FnBody.take());
|
||||
(void)Actions.ActOnFinishFunctionBody(MCDecl, FnBody.take());
|
||||
|
||||
if (Tok.getLocation() != OrigLoc) {
|
||||
// Due to parsing error, we either went over the cached tokens or
|
||||
|
@ -2878,5 +2897,5 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
|
|||
ConsumeAnyToken();
|
||||
}
|
||||
|
||||
return MDecl;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -766,14 +766,16 @@ bool Parser::isDeclarationAfterDeclarator() {
|
|||
if (KW.is(tok::kw_default) || KW.is(tok::kw_delete))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return Tok.is(tok::equal) || // int X()= -> not a function def
|
||||
Tok.is(tok::comma) || // int X(), -> not a function def
|
||||
Tok.is(tok::semi) || // int X(); -> not a function def
|
||||
Tok.is(tok::kw_asm) || // int X() __asm__ -> not a function def
|
||||
Tok.is(tok::kw___attribute) || // int X() __attr__ -> not a function def
|
||||
(getLangOpts().CPlusPlus &&
|
||||
Tok.is(tok::l_paren)); // int X(0) -> not a function def [C++]
|
||||
Tok.is(tok::l_paren)) || // int X(0) -> not a function def [C++]
|
||||
(CurParsedObjCImpl &&
|
||||
Tok.is(tok::l_brace)); // C-function nested in an @implementation
|
||||
}
|
||||
|
||||
/// \brief Determine whether the current token, if it occurs after a
|
||||
|
|
|
@ -265,12 +265,36 @@ void Sema::AddAnyMethodToGlobalPool(Decl *D) {
|
|||
AddFactoryMethodToGlobalPool(MDecl, true);
|
||||
}
|
||||
|
||||
/// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible
|
||||
/// and user declared, in the method definition's AST.
|
||||
void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
|
||||
assert(getCurMethodDecl() == 0 && "Method parsing confused");
|
||||
/// ActOnStartOfObjCMethodOrCFunctionDef - This routine sets up parameters; invisible
|
||||
/// and user declared, in the method definition's AST. This routine is also called
|
||||
/// for C-functions defined in an Objective-c class implementation.
|
||||
void Sema::ActOnStartOfObjCMethodOrCFunctionDef(Scope *FnBodyScope, Decl *D,
|
||||
bool parseMethod) {
|
||||
assert((getCurMethodDecl() == 0 && getCurFunctionDecl() == 0) &&
|
||||
"Method/c-function parsing confused");
|
||||
if (!parseMethod) {
|
||||
FunctionDecl *FDecl = FDecl = dyn_cast_or_null<FunctionDecl>(D);
|
||||
// If we don't have a valid c-function decl, simply return.
|
||||
if (!FDecl)
|
||||
return;
|
||||
PushDeclContext(FnBodyScope, FDecl);
|
||||
PushFunctionScope();
|
||||
|
||||
for (FunctionDecl::param_const_iterator PI = FDecl->param_begin(),
|
||||
E = FDecl->param_end(); PI != E; ++PI) {
|
||||
ParmVarDecl *Param = (*PI);
|
||||
if (!Param->isInvalidDecl() &&
|
||||
RequireCompleteType(Param->getLocation(), Param->getType(),
|
||||
diag::err_typecheck_decl_incomplete_type))
|
||||
Param->setInvalidDecl();
|
||||
if ((*PI)->getIdentifier())
|
||||
PushOnScopeChains(*PI, FnBodyScope);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ObjCMethodDecl *MDecl = dyn_cast_or_null<ObjCMethodDecl>(D);
|
||||
|
||||
|
||||
// If we don't have a valid method decl, simply return.
|
||||
if (!MDecl)
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -Werror -verify -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -x objective-c++ -fsyntax-only -Werror -verify -Wno-objc-root-class %s
|
||||
// rdar://10387088
|
||||
|
||||
@interface MyClass
|
||||
- (void)someMethod;
|
||||
@end
|
||||
|
||||
@implementation MyClass
|
||||
- (void)someMethod {
|
||||
[self privateMethod]; // clang already does not warn here
|
||||
}
|
||||
|
||||
int bar(MyClass * myObject) {
|
||||
[myObject privateMethod];
|
||||
return gorfbar(myObject);
|
||||
}
|
||||
- (void)privateMethod { }
|
||||
|
||||
int gorfbar(MyClass * myObject) {
|
||||
[myObject privateMethod];
|
||||
[myObject privateMethod1];
|
||||
return getMe + bar(myObject);
|
||||
}
|
||||
|
||||
- (void)privateMethod1 {
|
||||
getMe = getMe+1;
|
||||
}
|
||||
|
||||
static int getMe;
|
||||
|
||||
@end
|
Загрузка…
Ссылка в новой задаче