diff options
Diffstat (limited to 'lib/Parse')
-rw-r--r-- | lib/Parse/AttributeList.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/DeclSpec.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/MinimalAction.cpp | 37 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 50 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 112 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 16 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 106 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 33 | ||||
-rw-r--r-- | lib/Parse/ParseInit.cpp | 132 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 350 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 12 |
13 files changed, 641 insertions, 237 deletions
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index 3cd74d57f56d..bae2a09a9882 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -23,7 +23,7 @@ AttributeList::AttributeList(IdentifierInfo *aName, SourceLocation aLoc, AttributeList *n, bool declspec, bool cxx0x) : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), ScopeLoc(sLoc), ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(n), - DeclspecAttribute(declspec), CXX0XAttribute(cxx0x) { + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) { if (numArgs == 0) Args = 0; @@ -105,6 +105,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("overloadable", AT_overloadable) .Case("address_space", AT_address_space) .Case("always_inline", AT_always_inline) + .Case("returns_twice", IgnoredAttribute) .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) .Case("ext_vector_type", AT_ext_vector_type) diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp index 11865ab97b84..5dc08b3dfa2c 100644 --- a/lib/Parse/DeclSpec.cpp +++ b/lib/Parse/DeclSpec.cpp @@ -433,6 +433,7 @@ void DeclSpec::SaveWrittenBuiltinSpecs() { void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); + SaveStorageSpecifierAsWritten(); // Check the type specifier components first. SourceManager &SrcMgr = PP.getSourceManager(); diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index 5f48897235ab..5a0376781175 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -26,11 +26,40 @@ ActionBase::~ActionBase() {} /// Out-of-line virtual destructor to provide home for Action class. Action::~Action() {} +Action::ObjCMessageKind Action::getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + TypeTy *&ReceiverType) { + ReceiverType = 0; + + if (IsSuper && !HasTrailingDot && S->isInObjcMethodScope()) + return ObjCSuperMessage; + + if (TypeTy *TyName = getTypeName(*Name, NameLoc, S)) { + DeclSpec DS; + const char *PrevSpec = 0; + unsigned DiagID = 0; + if (!DS.SetTypeSpecType(DeclSpec::TST_typename, NameLoc, PrevSpec, + DiagID, TyName)) { + DS.SetRangeEnd(NameLoc); + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Ty = ActOnTypeName(S, DeclaratorInfo); + if (!Ty.isInvalid()) + ReceiverType = Ty.get(); + } + return ObjCClassMessage; + } + + return ObjCInstanceMessage; +} + // Defined out-of-line here because of dependecy on AttributeList Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList) { @@ -47,7 +76,7 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool IsTypeName, @@ -144,7 +173,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { /// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking. Action::TypeTy * MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc, - Scope *S, const CXXScopeSpec *SS, + Scope *S, CXXScopeSpec *SS, bool isClassName, TypeTy *ObjectType) { if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>()) if (TI->isTypeName) @@ -161,7 +190,7 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *, TemplateNameKind MinimalAction::isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringScope, diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 87e22fa9dce0..5405c0cb78ef 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -29,12 +29,14 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, "Current token not a '{', ':' or 'try'!"); Action::MultiTemplateParamsArg TemplateParams(Actions, - TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, - TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); + DeclPtrTy FnD; if (D.getDeclSpec().isFriendSpecified()) // FIXME: Friend templates - FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams)); + FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, + move(TemplateParams)); else // FIXME: pass template information through FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, move(TemplateParams), 0, 0, @@ -53,7 +55,7 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, // We may have a constructor initializer or function-try-block here. if (kind == tok::colon || kind == tok::kw_try) { // Consume everything up to (and including) the left brace. - if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) { + if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) { // We didn't find the left-brace we expected after the // constructor initializer. if (Tok.is(tok::semi)) { @@ -72,13 +74,13 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, ConsumeBrace(); } // Consume everything up to (and including) the matching right brace. - ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); // If we're in a function-try-block, we need to store all the catch blocks. if (kind == tok::kw_try) { while (Tok.is(tok::kw_catch)) { - ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks); - ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); } } @@ -98,7 +100,8 @@ void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { // The current scope is still active if we're the top-level class. // Otherwise we'll need to push and enter a new scope. bool HasClassScope = !Class.TopLevelClass; - ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope); + ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, + HasClassScope); if (HasClassScope) Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); @@ -217,12 +220,17 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { "ParseFunctionTryBlock left tokens in the token stream!"); continue; } - if (Tok.is(tok::colon)) + if (Tok.is(tok::colon)) { ParseConstructorInitializer(LM.D); - else + + // Error recovery. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions)); + continue; + } + } else Actions.ActOnDefaultCtorInitializers(LM.D); - // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'?? ParseFunctionStatementBody(LM.D); assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && @@ -238,14 +246,12 @@ void Parser::ParseLexedMethodDefs(ParsingClass &Class) { /// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets /// consumed/stored too, if ConsumeFinalToken). -/// If EarlyAbortIf is specified, then we will stop early if we find that -/// token at the top level. +/// If StopAtSemi is true, then we will stop early at a ';' character. /// Returns true if token 'T1' or 'T2' was found. /// NOTE: This is a specialized version of Parser::SkipUntil. bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, CachedTokens &Toks, - tok::TokenKind EarlyAbortIf, - bool ConsumeFinalToken) { + bool StopAtSemi, bool ConsumeFinalToken) { // We always want this function to consume at least one token if the first // token isn't T and if not at EOF. bool isFirstTokenConsumed = true; @@ -259,10 +265,6 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, return true; } - // If we found the early-abort token, return. - if (Tok.is(EarlyAbortIf)) - return false; - switch (Tok.getKind()) { case tok::eof: // Ran out of tokens. @@ -272,19 +274,19 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, // Recursively consume properly-nested parens. Toks.push_back(Tok); ConsumeParen(); - ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); break; case tok::l_square: // Recursively consume properly-nested square brackets. Toks.push_back(Tok); ConsumeBracket(); - ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); break; case tok::l_brace: // Recursively consume properly-nested braces. Toks.push_back(Tok); ConsumeBrace(); - ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. @@ -316,6 +318,10 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, Toks.push_back(Tok); ConsumeStringToken(); break; + case tok::semi: + if (StopAtSemi) + return false; + // FALL THROUGH. default: // consume this token. Toks.push_back(Tok); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c85b6ee9746c..91050e0a4cf9 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -904,7 +904,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // reinforced by the NAD status of core issue 635. TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); - if (DSContext == DSC_top_level && TemplateId->Name && + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && + TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, CurScope, &SS)) { if (isConstructorDeclarator()) { // The user meant this to be an out-of-line constructor @@ -949,7 +951,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If we're in a context where the identifier could be a class name, // check whether this is a constructor declaration. - if (DSContext == DSC_top_level && + if ((DSContext == DSC_top_level || + (DSContext == DSC_class && DS.isFriendSpecified())) && Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope, &SS)) { if (isConstructorDeclarator()) @@ -1434,6 +1437,11 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, switch (Tok.getKind()) { case tok::identifier: // foo::bar + // If we already have a type specifier, this identifier is not a type. + if (DS.getTypeSpecType() != DeclSpec::TST_unspecified || + DS.getTypeSpecWidth() != DeclSpec::TSW_unspecified || + DS.getTypeSpecSign() != DeclSpec::TSS_unspecified) + return false; // Check for need to substitute AltiVec keyword tokens. if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; @@ -1892,15 +1900,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - // enums cannot be templates. - if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { - Diag(Tok, diag::err_enum_template); - - // Skip the rest of this declarator, up until the comma or semicolon. - SkipUntil(tok::comma, true); - return; - } - // If an identifier is present, consume and remember it. IdentifierInfo *Name = 0; SourceLocation NameLoc; @@ -1924,23 +1923,69 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, TUK = Action::TUK_Declaration; else TUK = Action::TUK_Reference; + + // enums cannot be templates, although they can be referenced from a + // template. + if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + TUK != Action::TUK_Reference) { + Diag(Tok, diag::err_enum_template); + + // Skip the rest of this declarator, up until the comma or semicolon. + SkipUntil(tok::comma, true); + return; + } + bool Owned = false; bool IsDependent = false; + SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; + const char *PrevSpec = 0; + unsigned DiagID; DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK, StartLoc, SS, Name, NameLoc, Attr.get(), AS, Action::MultiTemplateParamsArg(Actions), Owned, IsDependent); - assert(!IsDependent && "didn't expect dependent enum"); + if (IsDependent) { + // This enum has a dependent nested-name-specifier. Handle it as a + // dependent tag. + if (!Name) { + DS.SetTypeSpecError(); + Diag(Tok, diag::err_expected_type_name_after_typename); + return; + } + + TypeResult Type = Actions.ActOnDependentTag(CurScope, DeclSpec::TST_enum, + TUK, SS, Name, StartLoc, + NameLoc); + if (Type.isInvalid()) { + DS.SetTypeSpecError(); + return; + } + + if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID, + Type.get(), false)) + Diag(StartLoc, DiagID) << PrevSpec; + + return; + } + if (!TagDecl.get()) { + // The action failed to produce an enumeration tag. If this is a + // definition, consume the entire definition. + if (Tok.is(tok::l_brace)) { + ConsumeBrace(); + SkipUntil(tok::r_brace); + } + + DS.SetTypeSpecError(); + return; + } + if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); // FIXME: The DeclSpec should keep the locations of both the keyword and the // name (if there is one). - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; - const char *PrevSpec = 0; - unsigned DiagID; if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, TagDecl.getAs<void>(), Owned)) Diag(StartLoc, DiagID) << PrevSpec; @@ -2427,7 +2472,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, true); // ignore fail - if (SS.isSet()) { + if (SS.isNotEmpty()) { if (Tok.isNot(tok::star)) { // The scope spec really belongs to the direct-declarator. D.getCXXScopeSpec() = SS; @@ -2583,36 +2628,42 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (getLang().CPlusPlus && D.mayHaveIdentifier()) { // ParseDeclaratorInternal might already have parsed the scope. - bool afterCXXScope = D.getCXXScopeSpec().isSet(); - if (!afterCXXScope) { + if (D.getCXXScopeSpec().isEmpty()) { ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec(), /*ObjectType=*/0, true); - afterCXXScope = D.getCXXScopeSpec().isSet(); } - if (afterCXXScope) { + if (D.getCXXScopeSpec().isValid()) { if (Actions.ShouldEnterDeclaratorScope(CurScope, D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function // is exited (and the declarator has been parsed). DeclScopeObj.EnterDeclaratorScope(); - } - + } + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { // We found something that indicates the start of an unqualified-id. // Parse that unqualified-id. - bool AllowConstructorName - = ((D.getCXXScopeSpec().isSet() && - D.getContext() == Declarator::FileContext) || - (!D.getCXXScopeSpec().isSet() && - D.getContext() == Declarator::MemberContext)) && - !D.getDeclSpec().hasTypeSpecifier(); + bool AllowConstructorName; + if (D.getDeclSpec().hasTypeSpecifier()) + AllowConstructorName = false; + else if (D.getCXXScopeSpec().isSet()) + AllowConstructorName = + (D.getContext() == Declarator::FileContext || + (D.getContext() == Declarator::MemberContext && + D.getDeclSpec().isFriendSpecified())); + else + AllowConstructorName = (D.getContext() == Declarator::MemberContext); + if (ParseUnqualifiedId(D.getCXXScopeSpec(), /*EnteringContext=*/true, /*AllowDestructorName=*/true, AllowConstructorName, /*ObjectType=*/0, - D.getName())) { + D.getName()) || + // Once we're past the identifier, if the scope was bad, mark the + // whole declarator bad. + D.getCXXScopeSpec().isInvalid()) { D.SetIdentifier(0, Tok.getLocation()); D.setInvalidType(true); } else { @@ -2974,7 +3025,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, DefArgToks = new CachedTokens; if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks, - tok::semi, false)) { + /*StopAtSemi=*/true, + /*ConsumeFinalToken=*/false)) { delete DefArgToks; DefArgToks = 0; Actions.ActOnParamDefaultArgumentError(Param); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 813c24ce3d58..015ac5b5dddd 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -178,7 +178,7 @@ Parser::DeclPtrTy Parser::ParseLinkage(ParsingDeclSpec &DS, DeclPtrTy LinkageSpec = Actions.ActOnStartLinkageSpecification(CurScope, /*FIXME: */SourceLocation(), - Loc, Lang.data(), Lang.size(), + Loc, Lang, Tok.is(tok::l_brace)? Tok.getLocation() : SourceLocation()); @@ -465,7 +465,7 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { /// simple-template-id /// Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - const CXXScopeSpec *SS) { + CXXScopeSpec *SS) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId @@ -780,9 +780,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Action::DeclResult TagOrTempResult = true; // invalid Action::TypeResult TypeResult = true; // invalid - // FIXME: When TUK == TUK_Reference and we have a template-id, we need - // to turn that template-id into a type. - bool Owned = false; if (TemplateId) { // Explicit specialization, class template partial specialization, @@ -806,7 +803,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateArgsPtr, TemplateId->RAngleLoc, AttrList); - } else if (TUK == Action::TUK_Reference) { + + // Friend template-ids are treated as references unless + // they have template headers, in which case they're ill-formed + // (FIXME: "template <class T> friend class A<T>::B<int>;"). + // We diagnose this error in ActOnClassTemplateSpecialization. + } else if (TUK == Action::TUK_Reference || + (TUK == Action::TUK_Friend && + TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { TypeResult = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template), TemplateId->TemplateNameLoc, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index af91021d33ce..b9e632a1846e 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -29,30 +29,6 @@ #include "llvm/ADT/SmallString.h" using namespace clang; -/// PrecedenceLevels - These are precedences for the binary/ternary operators in -/// the C99 grammar. These have been named to relate with the C99 grammar -/// productions. Low precedences numbers bind more weakly than high numbers. -namespace prec { - enum Level { - Unknown = 0, // Not binary operator. - Comma = 1, // , - Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= - Conditional = 3, // ? - LogicalOr = 4, // || - LogicalAnd = 5, // && - InclusiveOr = 6, // | - ExclusiveOr = 7, // ^ - And = 8, // & - Equality = 9, // ==, != - Relational = 10, // >=, <=, >, < - Shift = 11, // <<, >> - Additive = 12, // -, + - Multiplicative = 13, // *, /, % - PointerToMember = 14 // .*, ->* - }; -} - - /// getBinOpPrecedence - Return the precedence of the specified binary operator /// token. This returns: /// @@ -268,11 +244,11 @@ Parser::OwningExprResult Parser::ParseAssignmentExpression() { /// expressions and other binary operators for these expressions as well. Parser::OwningExprResult Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc, - SourceLocation NameLoc, - IdentifierInfo *ReceiverName, + SourceLocation SuperLoc, + TypeTy *ReceiverType, ExprArg ReceiverExpr) { - OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, NameLoc, - ReceiverName, + OwningExprResult R(ParseObjCMessageExpressionBody(LBracLoc, SuperLoc, + ReceiverType, move(ReceiverExpr))); if (R.isInvalid()) return move(R); R = ParsePostfixExpressionSuffix(move(R)); @@ -297,10 +273,10 @@ Parser::OwningExprResult Parser::ParseConstantExpression() { /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with /// LHS and has a precedence of at least MinPrec. Parser::OwningExprResult -Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { - unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), - GreaterThanIsOperator, - getLang().CPlusPlus0x); +Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, prec::Level MinPrec) { + prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(), + GreaterThanIsOperator, + getLang().CPlusPlus0x); SourceLocation ColonLoc; while (1) { @@ -335,14 +311,15 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { Diag(Tok, diag::ext_gnu_conditional_expr); } - if (Tok.isNot(tok::colon)) { - Diag(Tok, diag::err_expected_colon); + if (Tok.is(tok::colon)) { + // Eat the colon. + ColonLoc = ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_colon) + << FixItHint::CreateInsertion(Tok.getLocation(), ": "); Diag(OpToken, diag::note_matching) << "?"; - return ExprError(); + ColonLoc = Tok.getLocation(); } - - // Eat the colon. - ColonLoc = ConsumeToken(); } // Parse another leaf here for the RHS of the operator. @@ -362,7 +339,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. - unsigned ThisPrec = NextTokPrec; + prec::Level ThisPrec = NextTokPrec; NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, getLang().CPlusPlus0x); @@ -379,7 +356,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. // The function takes ownership of the RHS. - RHS = ParseRHSOfBinaryExpression(move(RHS), ThisPrec + !isRightAssoc); + RHS = ParseRHSOfBinaryExpression(move(RHS), + static_cast<prec::Level>(ThisPrec + !isRightAssoc)); if (RHS.isInvalid()) return move(RHS); @@ -480,7 +458,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] -/// [C++] typename-specifier '(' expression-list[opt] ')' [TODO] +/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3] /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] @@ -500,14 +478,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// /// id-expression: [C++ 5.1] /// unqualified-id -/// qualified-id [TODO] +/// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id -/// conversion-function-id [TODO] -/// '~' class-name [TODO] -/// template-id [TODO] +/// conversion-function-id +/// '~' class-name +/// template-id /// /// new-expression: [C++ 5.3.4] /// '::'[opt] 'new' new-placement[opt] new-type-id @@ -637,11 +615,11 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation ILoc = ConsumeToken(); - // Support 'Class.property' notation. We don't use - // isTokObjCMessageIdentifierReceiver(), since it allows 'super' (which is - // inappropriate here). + // Support 'Class.property' and 'super.property' notation. if (getLang().ObjC1 && Tok.is(tok::period) && - Actions.getTypeName(II, ILoc, CurScope)) { + (Actions.getTypeName(II, ILoc, CurScope) || + // Allow the base to be 'super' if in an objc-method. + (&II == Ident_super && CurScope->isInObjcMethodScope()))) { SourceLocation DotLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) { @@ -810,6 +788,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::annot_cxxscope: { // [C++] id-expression: qualified-id + // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. + // (We can end up in this situation after tentative parsing.) + if (TryAnnotateTypeOrScopeToken()) + return ExprError(); + if (!Tok.is(tok::annot_cxxscope)) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); + Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId @@ -897,11 +883,16 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::caret: return ParsePostfixExpressionSuffix(ParseBlockLiteralExpression()); + case tok::code_completion: + Actions.CodeCompleteOrdinaryName(CurScope, Action::CCC_Expression); + ConsumeToken(); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, TypeOfCast); case tok::l_square: // These can be followed by postfix-expr pieces. if (getLang().ObjC1) return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); - // FALL THROUGH. + // FALL THROUGH. default: NotCastExpr = true; return ExprError(); @@ -1431,10 +1422,19 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, CastTy = Ty.get(); - if (stopIfCastExpr) { - // Note that this doesn't parse the subsequent cast-expression, it just - // returns the parsed type to the callee. + // Note that this doesn't parse the subsequent cast-expression, it just + // returns the parsed type to the callee. + if (stopIfCastExpr) return OwningExprResult(Actions); + + // Reject the cast of super idiom in ObjC. + if (Tok.is(tok::identifier) && getLang().ObjC1 && + Tok.getIdentifierInfo() == Ident_super && + CurScope->isInObjcMethodScope() && + GetLookAheadToken(1).isNot(tok::period)) { + Diag(Tok.getLocation(), diag::err_illegal_super_cast) + << SourceRange(OpenLoc, RParenLoc); + return ExprError(); } // Parse the cast-expression that follows it next. diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 8528f8fe190c..146762b83ad5 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -749,6 +749,36 @@ bool Parser::ParseCXXCondition(OwningExprResult &ExprResult, return false; } +/// \brief Determine whether the current token starts a C++ +/// simple-type-specifier. +bool Parser::isCXXSimpleTypeSpecifier() const { + switch (Tok.getKind()) { + case tok::annot_typename: + case tok::kw_short: + case tok::kw_long: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_float: + case tok::kw_double: + case tok::kw_wchar_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_bool: + // FIXME: C++0x decltype support. + // GNU typeof support. + case tok::kw_typeof: + return true; + + default: + break; + } + + return false; +} + /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. /// This should only be called when the current token is known to be part of /// simple-type-specifier. @@ -837,6 +867,7 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, DiagID); break; + // FIXME: C++0x decltype support. // GNU typeof support. case tok::kw_typeof: ParseTypeofSpecifier(DS); @@ -1703,7 +1734,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // Store the tokens of the parentheses. We will parse them after we determine // the context that follows them. - if (!ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks, tok::semi)) { + if (!ConsumeAndStoreUntil(tok::r_paren, Toks)) { // We didn't find the ')' we expected. MatchRHSPunctuation(tok::r_paren, LParenLoc); return ExprError(); diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 9154d8d59987..a382a9ae3c40 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Designator.h" #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Scope.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -33,6 +34,19 @@ static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) { } } +static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc, + Designation &Desig) { + // If we have exactly one array designator, this used the GNU + // 'designation: array-designator' extension, otherwise there should be no + // designators at all! + if (Desig.getNumDesignators() == 1 && + (Desig.getDesignator(0).isArrayDesignator() || + Desig.getDesignator(0).isArrayRangeDesignator())) + P.Diag(Loc, diag::ext_gnu_missing_equal_designator); + else if (Desig.getNumDesignators() > 0) + P.Diag(Loc, diag::err_expected_equal_designator); +} + /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production /// checking to see if the token stream starts with a designator. /// @@ -123,33 +137,97 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { // [4][foo bar] -> obsolete GNU designation with objc message send. // SourceLocation StartLoc = ConsumeBracket(); + OwningExprResult Idx(Actions); + + // If Objective-C is enabled and this is a typename (class message + // send) or send to 'super', parse this as a message send + // expression. We handle C++ and C separately, since C++ requires + // much more complicated parsing. + if (getLang().ObjC1 && getLang().CPlusPlus) { + // Send to 'super'. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), 0, + ExprArg(Actions)); + } + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); + } + + // If the receiver was a type, we have a class message; parse + // the rest of it. + if (!IsExpr) { + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + TypeOrExpr, + ExprArg(Actions)); + } - // If Objective-C is enabled and this is a typename or other identifier - // receiver, parse this as a message send expression. - if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) { - // If we have exactly one array designator, this used the GNU - // 'designation: array-designator' extension, otherwise there should be no - // designators at all! - if (Desig.getNumDesignators() == 1 && - (Desig.getDesignator(0).isArrayDesignator() || - Desig.getDesignator(0).isArrayRangeDesignator())) - Diag(StartLoc, diag::ext_gnu_missing_equal_designator); - else if (Desig.getNumDesignators() > 0) - Diag(Tok, diag::err_expected_equal_designator); - - IdentifierInfo *Name = Tok.getIdentifierInfo(); - SourceLocation NameLoc = ConsumeToken(); - return ParseAssignmentExprWithObjCMessageExprStart( - StartLoc, NameLoc, Name, ExprArg(Actions)); + // If the receiver was an expression, we still don't know + // whether we have a message send or an array designator; just + // adopt the expression for further analysis below. + // FIXME: potentially-potentially evaluated expression above? + Idx = OwningExprResult(Actions, TypeOrExpr); + } else if (getLang().ObjC1 && Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + SourceLocation IILoc = Tok.getLocation(); + TypeTy *ReceiverType; + // Three cases. This is a message send to a type: [type foo] + // This is a message send to super: [super foo] + // This is a message sent to an expr: [super.bar foo] + switch (Action::ObjCMessageKind Kind + = Actions.getObjCMessageKind(CurScope, II, IILoc, + II == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Action::ObjCSuperMessage: + case Action::ObjCClassMessage: + CheckArrayDesignatorSyntax(*this, StartLoc, Desig); + if (Kind == Action::ObjCSuperMessage) + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + ConsumeToken(), + 0, + ExprArg(Actions)); + ConsumeToken(); // the identifier + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, + SourceLocation(), + ReceiverType, + ExprArg(Actions)); + + case Action::ObjCInstanceMessage: + // Fall through; we'll just parse the expression and + // (possibly) treat this like an Objective-C message send + // later. + break; + } } + // Parse the index expression, if we haven't already gotten one + // above (which can only happen in Objective-C++). // Note that we parse this as an assignment expression, not a constant // expression (allowing *=, =, etc) to handle the objc case. Sema needs // to validate that the expression is a constant. - OwningExprResult Idx(ParseAssignmentExpression()); - if (Idx.isInvalid()) { - SkipUntil(tok::r_square); - return move(Idx); + // FIXME: We also need to tell Sema that we're in a + // potentially-potentially evaluated context. + if (!Idx.get()) { + Idx = ParseAssignmentExpression(); + if (Idx.isInvalid()) { + SkipUntil(tok::r_square); + return move(Idx); + } } // Given an expression, we could either have a designator (if the next @@ -158,17 +236,7 @@ Parser::OwningExprResult Parser::ParseInitializerWithPotentialDesignator() { // an assignment-expression production. if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && Tok.isNot(tok::r_square)) { - - // If we have exactly one array designator, this used the GNU - // 'designation: array-designator' extension, otherwise there should be no - // designators at all! - if (Desig.getNumDesignators() == 1 && - (Desig.getDesignator(0).isArrayDesignator() || - Desig.getDesignator(0).isArrayRangeDesignator())) - Diag(StartLoc, diag::ext_gnu_missing_equal_designator); - else if (Desig.getNumDesignators() > 0) - Diag(Tok, diag::err_expected_equal_designator); - + CheckArrayDesignatorSyntax(*this, Tok.getLocation(), Desig); return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, SourceLocation(), 0, move(Idx)); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 243be0ed45ae..7b1ecf6437dc 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -142,13 +142,13 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( // We have a class or category name - consume it. IdentifierInfo *nameId = Tok.getIdentifierInfo(); SourceLocation nameLoc = ConsumeToken(); - bool Err = false; - if (Tok.is(tok::l_paren)) { // we have a category. + if (Tok.is(tok::l_paren) && + !isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { // we have a category. SourceLocation lparenLoc = ConsumeParen(); SourceLocation categoryLoc, rparenLoc; IdentifierInfo *categoryId = 0; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId); + Actions.CodeCompleteObjCInterfaceCategory(CurScope, nameId, nameLoc); ConsumeToken(); } @@ -157,12 +157,6 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( categoryId = Tok.getIdentifierInfo(); categoryLoc = ConsumeToken(); } - else if (isKnownToBeTypeSpecifier(Tok)) { - // Fall thru after diagnosing for better error recovery. - Diag(Tok, diag::err_expected_minus_or_plus); - ConsumeToken(); - Err = true; - } else if (!getLang().ObjC2) { Diag(Tok, diag::err_expected_ident); // missing category name. return DeclPtrTy(); @@ -173,34 +167,32 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( return DeclPtrTy(); } rparenLoc = ConsumeParen(); - if (!Err) { - // Next, we need to check for any protocol references. - SourceLocation LAngleLoc, EndProtoLoc; - llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; - llvm::SmallVector<SourceLocation, 8> ProtocolLocs; - if (Tok.is(tok::less) && - ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, + // Next, we need to check for any protocol references. + SourceLocation LAngleLoc, EndProtoLoc; + llvm::SmallVector<DeclPtrTy, 8> ProtocolRefs; + llvm::SmallVector<SourceLocation, 8> ProtocolLocs; + if (Tok.is(tok::less) && + ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, LAngleLoc, EndProtoLoc)) - return DeclPtrTy(); + return DeclPtrTy(); - if (attrList) // categories don't support attributes. - Diag(Tok, diag::err_objc_no_attributes_on_category); - - DeclPtrTy CategoryType = - Actions.ActOnStartCategoryInterface(atLoc, - nameId, nameLoc, - categoryId, categoryLoc, - ProtocolRefs.data(), - ProtocolRefs.size(), - ProtocolLocs.data(), - EndProtoLoc); - if (Tok.is(tok::l_brace)) + if (attrList) // categories don't support attributes. + Diag(Tok, diag::err_objc_no_attributes_on_category); + + DeclPtrTy CategoryType = + Actions.ActOnStartCategoryInterface(atLoc, + nameId, nameLoc, + categoryId, categoryLoc, + ProtocolRefs.data(), + ProtocolRefs.size(), + ProtocolLocs.data(), + EndProtoLoc); + if (Tok.is(tok::l_brace)) ParseObjCClassInstanceVariables(CategoryType, tok::objc_private, atLoc); - ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); - return CategoryType; - } + ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword); + return CategoryType; } // Parse a class interface. IdentifierInfo *superClassId = 0; @@ -211,7 +203,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( // Code completion of superclass names. if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCSuperclass(CurScope, nameId); + Actions.CodeCompleteObjCSuperclass(CurScope, nameId, nameLoc); ConsumeToken(); } @@ -242,7 +234,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration( ParseObjCClassInstanceVariables(ClsType, tok::objc_protected, atLoc); ParseObjCInterfaceDeclList(ClsType, tok::objc_interface); - return Err ? DeclPtrTy() : ClsType; + return ClsType; } /// The Objective-C property callback. This should be defined where @@ -787,6 +779,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::ObjCKeywordKind MethodImplKind) { ParsingDeclRAIIObject PD(*this); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, + /*ReturnType=*/0, IDecl); + ConsumeToken(); + } + // Parse the return type if present. TypeTy *ReturnType = 0; ObjCDeclSpec DSRet; @@ -798,6 +796,12 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) MethodAttrs.reset(ParseGNUAttributes()); + if (Tok.is(tok::code_completion)) { + Actions.CodeCompleteObjCMethodDecl(CurScope, mType == tok::minus, + ReturnType, IDecl); + ConsumeToken(); + } + // Now parse the selector. SourceLocation selLoc; IdentifierInfo *SelIdent = ParseObjCSelectorPiece(selLoc); @@ -811,7 +815,7 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, return DeclPtrTy(); } - llvm::SmallVector<Declarator, 8> CargNames; + llvm::SmallVector<DeclaratorChunk::ParamInfo, 8> CParamInfo; if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. if (getLang().ObjC2 && Tok.is(tok::kw___attribute)) @@ -822,7 +826,9 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, DeclPtrTy Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, - 0, CargNames, MethodAttrs.get(), + 0, + CParamInfo.data(), CParamInfo.size(), + MethodAttrs.get(), MethodImplKind); PD.complete(Result); return Result; @@ -885,7 +891,13 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, // Parse the declarator. Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); - CargNames.push_back(ParmDecl); + IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + DeclPtrTy Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl); + CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, + ParmDecl.getIdentifierLoc(), + Param, + 0)); + } // FIXME: Add support for optional parmameter list... @@ -901,7 +913,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDecl(SourceLocation mLoc, DeclPtrTy Result = Actions.ActOnMethodDeclaration(mLoc, Tok.getLocation(), mType, IDecl, DSRet, ReturnType, Sel, - &ArgInfos[0], CargNames, + &ArgInfos[0], + CParamInfo.data(), CParamInfo.size(), MethodAttrs.get(), MethodImplKind, isVariadic); PD.complete(Result); @@ -1053,7 +1066,8 @@ void Parser::ParseObjCClassInstanceVariables(DeclPtrTy interfaceDecl, = P.Actions.ActOnIvar(P.CurScope, FD.D.getDeclSpec().getSourceRange().getBegin(), IDecl, FD.D, FD.BitfieldSize, visibility); - AllIvarDecls.push_back(Field); + if (Field) + AllIvarDecls.push_back(Field); return Field; } } Callback(*this, interfaceDecl, visibility, AllIvarDecls); @@ -1207,7 +1221,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtImplementationDeclaration( IdentifierInfo *categoryId = 0; if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId); + Actions.CodeCompleteObjCImplementationCategory(CurScope, nameId, nameLoc); ConsumeToken(); } @@ -1404,8 +1418,12 @@ Parser::DeclPtrTy Parser::ParseObjCPropertyDynamic(SourceLocation atLoc) { break; ConsumeToken(); // consume ',' } - if (Tok.isNot(tok::semi)) + if (Tok.isNot(tok::semi)) { Diag(Tok, diag::err_expected_semi_after) << "@dynamic"; + SkipUntil(tok::semi); + } + else + ConsumeToken(); // consume ';' return DeclPtrTy(); } @@ -1422,7 +1440,8 @@ Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) { return StmtError(); } } - ConsumeToken(); // consume ';' + // consume ';' + ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "@throw"); return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope); } @@ -1482,7 +1501,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Diag(Tok, diag::err_expected_lbrace); return StmtError(); } - OwningStmtResult CatchStmts(Actions); + StmtVector CatchStmts(Actions); OwningStmtResult FinallyStmt(Actions); ParseScope TryScope(this, Scope::DeclScope); OwningStmtResult TryBody(ParseCompoundStatementBody()); @@ -1515,11 +1534,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Declarator ParmDecl(DS, Declarator::PrototypeContext); ParseDeclarator(ParmDecl); - // Inform the actions module about the parameter declarator, so it + // Inform the actions module about the declarator, so it // gets added to the current scope. - // FIXME. Probably can build a VarDecl and avoid setting DeclContext. - FirstPart = Actions.ActOnParamDeclarator(CurScope, ParmDecl); - Actions.ActOnObjCCatchParam(FirstPart); + FirstPart = Actions.ActOnObjCExceptionDecl(CurScope, ParmDecl); } else ConsumeToken(); // consume '...' @@ -1537,9 +1554,14 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Diag(Tok, diag::err_expected_lbrace); if (CatchBody.isInvalid()) CatchBody = Actions.ActOnNullStmt(Tok.getLocation()); - CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, - RParenLoc, FirstPart, move(CatchBody), - move(CatchStmts)); + + OwningStmtResult Catch = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, + RParenLoc, + FirstPart, + move(CatchBody)); + if (!Catch.isInvalid()) + CatchStmts.push_back(Catch.release()); + } else { Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after) << "@catch clause"; @@ -1568,7 +1590,9 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Diag(atLoc, diag::err_missing_catch_finally); return StmtError(); } - return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), move(CatchStmts), + + return Actions.ActOnObjCAtTryStmt(atLoc, move(TryBody), + move_arg(CatchStmts), move(FinallyStmt)); } @@ -1604,7 +1628,8 @@ Parser::DeclPtrTy Parser::ParseObjCMethodDefinition() { SourceLocation BraceLoc = Tok.getLocation(); // Enter a scope for the method body. - ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + ParseScope BodyScope(this, + Scope::ObjCMethodScope|Scope::FnScope|Scope::DeclScope); // Tell the actions module that we have entered a method definition with the // specified Declarator for the method. @@ -1683,39 +1708,191 @@ Parser::OwningExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { } } +/// \brirg Parse the receiver of an Objective-C++ message send. +/// +/// This routine parses the receiver of a message send in +/// Objective-C++ either as a type or as an expression. Note that this +/// routine must not be called to parse a send to 'super', since it +/// has no way to return such a result. +/// +/// \param IsExpr Whether the receiver was parsed as an expression. +/// +/// \param TypeOrExpr If the receiver was parsed as an expression (\c +/// IsExpr is true), the parsed expression. If the receiver was parsed +/// as a type (\c IsExpr is false), the parsed type. +/// +/// \returns True if an error occurred during parsing or semantic +/// analysis, in which case the arguments do not have valid +/// values. Otherwise, returns false for a successful parse. +/// +/// objc-receiver: [C++] +/// 'super' [not parsed here] +/// expression +/// simple-type-specifier +/// typename-specifier + +bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { + if (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_typename) || Tok.is(tok::annot_cxxscope)) + TryAnnotateTypeOrScopeToken(); + + if (!isCXXSimpleTypeSpecifier()) { + // objc-receiver: + // expression + OwningExprResult Receiver = ParseExpression(); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // objc-receiver: + // typename-specifier + // simple-type-specifier + // expression (that starts with one of the above) + DeclSpec DS; + ParseCXXSimpleTypeSpecifier(DS); + + if (Tok.is(tok::l_paren)) { + // If we see an opening parentheses at this point, we are + // actually parsing an expression that starts with a + // function-style cast, e.g., + // + // postfix-expression: + // simple-type-specifier ( expression-list [opt] ) + // typename-specifier ( expression-list [opt] ) + // + // Parse the remainder of this case, then the (optional) + // postfix-expression suffix, followed by the (optional) + // right-hand side of the binary expression. We have an + // instance method. + OwningExprResult Receiver = ParseCXXTypeConstructExpression(DS); + if (!Receiver.isInvalid()) + Receiver = ParsePostfixExpressionSuffix(move(Receiver)); + if (!Receiver.isInvalid()) + Receiver = ParseRHSOfBinaryExpression(move(Receiver), prec::Comma); + if (Receiver.isInvalid()) + return true; + + IsExpr = true; + TypeOrExpr = Receiver.take(); + return false; + } + + // We have a class message. Turn the simple-type-specifier or + // typename-specifier we parsed into a type and parse the + // remainder of the class message. + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + TypeResult Type = Actions.ActOnTypeName(CurScope, DeclaratorInfo); + if (Type.isInvalid()) + return true; + + IsExpr = false; + TypeOrExpr = Type.get(); + return false; +} + /// objc-message-expr: /// '[' objc-receiver objc-message-args ']' /// -/// objc-receiver: +/// objc-receiver: [C] +/// 'super' /// expression /// class-name /// type-name +/// Parser::OwningExprResult Parser::ParseObjCMessageExpression() { assert(Tok.is(tok::l_square) && "'[' expected"); SourceLocation LBracLoc = ConsumeBracket(); // consume '[' - // Parse receiver - if (isTokObjCMessageIdentifierReceiver()) { - IdentifierInfo *ReceiverName = Tok.getIdentifierInfo(); - if (ReceiverName != Ident_super || GetLookAheadToken(1).isNot(tok::period)) { - SourceLocation NameLoc = ConsumeToken(); - return ParseObjCMessageExpressionBody(LBracLoc, NameLoc, ReceiverName, + if (getLang().CPlusPlus) { + // We completely separate the C and C++ cases because C++ requires + // more complicated (read: slower) parsing. + + // Handle send to super. + // FIXME: This doesn't benefit from the same typo-correction we + // get in Objective-C. + if (Tok.is(tok::identifier) && Tok.getIdentifierInfo() == Ident_super && + NextToken().isNot(tok::period) && CurScope->isInObjcMethodScope()) + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, ExprArg(Actions)); + + // Parse the receiver, which is either a type or an expression. + bool IsExpr; + void *TypeOrExpr; + if (ParseObjCXXMessageReceiver(IsExpr, TypeOrExpr)) { + SkipUntil(tok::r_square); + return ExprError(); } - } + if (IsExpr) + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, + OwningExprResult(Actions, TypeOrExpr)); + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + TypeOrExpr, ExprArg(Actions)); + } else if (Tok.is(tok::identifier)) { + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + TypeTy *ReceiverType; + switch (Actions.getObjCMessageKind(CurScope, Name, NameLoc, + Name == Ident_super, + NextToken().is(tok::period), + ReceiverType)) { + case Action::ObjCSuperMessage: + return ParseObjCMessageExpressionBody(LBracLoc, ConsumeToken(), 0, + ExprArg(Actions)); + + case Action::ObjCClassMessage: + if (!ReceiverType) { + SkipUntil(tok::r_square); + return ExprError(); + } + + ConsumeToken(); // the type name + + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), + ReceiverType, + ExprArg(Actions)); + + case Action::ObjCInstanceMessage: + // Fall through to parse an expression. + break; + } + } + + // Otherwise, an arbitrary expression can be the receiver of a send. OwningExprResult Res(ParseExpression()); if (Res.isInvalid()) { SkipUntil(tok::r_square); return move(Res); } - return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), - 0, move(Res)); + return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), 0, + move(Res)); } -/// ParseObjCMessageExpressionBody - Having parsed "'[' objc-receiver", parse -/// the rest of a message expression. +/// \brief Parse the remainder of an Objective-C message following the +/// '[' objc-receiver. +/// +/// This routine handles sends to super, class messages (sent to a +/// class name), and instance messages (sent to an object), and the +/// target is represented by \p SuperLoc, \p ReceiverType, or \p +/// ReceiverExpr, respectively. Only one of these parameters may have +/// a valid value. +/// +/// \param LBracLoc The location of the opening '['. +/// +/// \param SuperLoc If this is a send to 'super', the location of the +/// 'super' keyword that indicates a send to the superclass. +/// +/// \param ReceiverType If this is a class message, the type of the +/// class we are sending a message to. +/// +/// \param ReceiverExpr If this is an instance message, the expression +/// used to compute the receiver object. /// /// objc-message-args: /// objc-selector @@ -1737,13 +1914,14 @@ Parser::OwningExprResult Parser::ParseObjCMessageExpression() { /// Parser::OwningExprResult Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, - SourceLocation NameLoc, - IdentifierInfo *ReceiverName, + SourceLocation SuperLoc, + TypeTy *ReceiverType, ExprArg ReceiverExpr) { if (Tok.is(tok::code_completion)) { - if (ReceiverName) - Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc, - 0, 0); + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, 0, 0); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, 0, 0); else Actions.CodeCompleteObjCInstanceMessage(CurScope, ReceiverExpr.get(), 0, 0); @@ -1789,8 +1967,12 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // Code completion after each argument. if (Tok.is(tok::code_completion)) { - if (ReceiverName) - Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverName, NameLoc, + if (SuperLoc.isValid()) + Actions.CodeCompleteObjCSuperMessage(CurScope, SuperLoc, + KeyIdents.data(), + KeyIdents.size()); + else if (ReceiverType) + Actions.CodeCompleteObjCClassMessage(CurScope, ReceiverType, KeyIdents.data(), KeyIdents.size()); else @@ -1851,15 +2033,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, KeyIdents.push_back(selIdent); Selector Sel = PP.getSelectorTable().getSelector(nKeys, &KeyIdents[0]); - // We've just parsed a keyword message. - if (ReceiverName) - return Owned(Actions.ActOnClassMessage(CurScope, ReceiverName, Sel, - LBracLoc, NameLoc, SelectorLoc, - RBracLoc, - KeyExprs.take(), KeyExprs.size())); - return Owned(Actions.ActOnInstanceMessage(ReceiverExpr.release(), Sel, - LBracLoc, SelectorLoc, RBracLoc, - KeyExprs.take(), KeyExprs.size())); + if (SuperLoc.isValid()) + return Actions.ActOnSuperMessage(CurScope, SuperLoc, Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + else if (ReceiverType) + return Actions.ActOnClassMessage(CurScope, ReceiverType, Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); + return Actions.ActOnInstanceMessage(CurScope, move(ReceiverExpr), Sel, + LBracLoc, SelectorLoc, RBracLoc, + Action::MultiExprArg(Actions, + KeyExprs.take(), + KeyExprs.size())); } Parser::OwningExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index b208c50c81bc..9b2227002f1b 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -643,6 +643,7 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { if (Tok.is(tok::kw_else)) { ElseLoc = ConsumeToken(); + ElseStmtLoc = Tok.getLocation(); // C99 6.8.4p3 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do @@ -656,12 +657,14 @@ Parser::OwningStmtResult Parser::ParseIfStatement(AttributeList *Attr) { ParseScope InnerScope(this, Scope::DeclScope, C99orCXX && Tok.isNot(tok::l_brace)); - bool WithinElse = CurScope->isWithinElse(); - CurScope->setWithinElse(true); - ElseStmtLoc = Tok.getLocation(); + // Regardless of whether or not InnerScope actually pushed a scope, set the + // ElseScope flag for the innermost scope so we can diagnose use of the if + // condition variable in C++. + unsigned OldFlags = CurScope->getFlags(); + CurScope->setFlags(OldFlags | Scope::ElseScope); ElseStmt = ParseStatement(); - CurScope->setWithinElse(WithinElse); - + CurScope->setFlags(OldFlags); + // Pop the 'else' scope if needed. InnerScope.Exit(); } diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 516a9a620b62..a6c6d3f94535 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Template.h" using namespace clang; /// isCXXDeclarationStatement - C++-specialized function that disambiguates @@ -761,6 +762,17 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw___vector: return TPResult::True(); + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId + = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + if (TemplateId->Kind != TNK_Type_template) + return TPResult::False(); + CXXScopeSpec SS; + AnnotateTemplateIdTokenAsType(&SS); + assert(Tok.is(tok::annot_typename)); + goto case_typename; + } + case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed // We've already annotated a scope; try to annotate a type. if (TryAnnotateTypeOrScopeToken()) @@ -801,6 +813,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_double: case tok::kw_void: case tok::annot_typename: + case_typename: if (NextToken().is(tok::l_paren)) return TPResult::Ambiguous(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 489586c36f54..6dbb99e395f9 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -668,9 +668,15 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(ParsingDeclarator &D, // If we have a colon, then we're probably parsing a C++ // ctor-initializer. - if (Tok.is(tok::colon)) + if (Tok.is(tok::colon)) { ParseConstructorInitializer(Res); - else + + // Recover from error. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(Res, Action::StmtArg(Actions)); + return Res; + } + } else Actions.ActOnDefaultCtorInitializers(Res); return ParseFunctionStatementBody(Res); @@ -1046,7 +1052,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { CXXScopeSpec SS; if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/0, EnteringContext)) return true; - if (!SS.isSet()) + if (SS.isEmpty()) return false; // Push the current token back into the token stream (or revert it if it is |