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,
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;
}
bool Finished;
};
ObjCImplParsingDataRAII *CurParsedObjCImpl;
+ void StashAwayMethodOrFunctionBodyTokens(Decl *MDecl);
DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc);
DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
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);
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)) {
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(),
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() {
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);
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();
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());
// 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
ConsumeAnyToken();
}
- return MDecl;
+ return;
}
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
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;
--- /dev/null
+// 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