diff options
Diffstat (limited to 'lib/Parse/ParseDeclCXX.cpp')
| -rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 272 | 
1 files changed, 203 insertions, 69 deletions
| diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 87d99096440c..53e4a419682e 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -558,6 +558,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,    // Maybe this is an alias-declaration.    TypeResult TypeAlias;    bool IsAliasDecl = Tok.is(tok::equal); +  Decl *DeclFromDeclSpec = nullptr;    if (IsAliasDecl) {      // If we had any misplaced attributes from earlier, this is where they      // should have been written. @@ -612,10 +613,12 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,        Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier)          << FixItHint::CreateRemoval(SS.getRange()); -    TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind ? -                              Declarator::AliasTemplateContext : -                              Declarator::AliasDeclContext, AS, OwnedType, -                              &Attrs); +    TypeAlias = ParseTypeName(nullptr, TemplateInfo.Kind +                                           ? Declarator::AliasTemplateContext +                                           : Declarator::AliasDeclContext, +                              AS, &DeclFromDeclSpec, &Attrs); +    if (OwnedType) +      *OwnedType = DeclFromDeclSpec;    } else {      // C++11 attributes are not allowed on a using-declaration, but GNU ones      // are. @@ -664,7 +667,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context,        TemplateParams ? TemplateParams->size() : 0);      return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg,                                           UsingLoc, Name, Attrs.getList(), -                                         TypeAlias); +                                         TypeAlias, DeclFromDeclSpec);    }    return Actions.ActOnUsingDeclaration(getCurScope(), AS, @@ -796,7 +799,10 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {        //   The operand of the decltype specifier is an unevaluated operand.        EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated,                                                     nullptr,/*IsDecltype=*/true); -      Result = Actions.CorrectDelayedTyposInExpr(ParseExpression()); +      Result = +          Actions.CorrectDelayedTyposInExpr(ParseExpression(), [](Expr *E) { +            return E->hasPlaceholderType() ? ExprError() : E; +          });        if (Result.isInvalid()) {          DS.SetTypeSpecError();          if (SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch)) { @@ -1223,10 +1229,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,    ParsedAttributesWithRange attrs(AttrFactory);    // If attributes exist after tag, parse them.    MaybeParseGNUAttributes(attrs); - -  // If declspecs exist after tag, parse them. -  while (Tok.is(tok::kw___declspec)) -    ParseMicrosoftDeclSpec(attrs); +  MaybeParseMicrosoftDeclSpecs(attrs);    // Parse inheritance specifiers.    if (Tok.is(tok::kw___single_inheritance) || @@ -1310,11 +1313,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,      // is a base-specifier-list.      ColonProtectionRAIIObject X(*this); -    if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) +    CXXScopeSpec Spec; +    bool HasValidSpec = true; +    if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), EnteringContext)) {        DS.SetTypeSpecError(); -    if (SS.isSet()) -      if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) +      HasValidSpec = false; +    } +    if (Spec.isSet()) +      if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) {          Diag(Tok, diag::err_expected) << tok::identifier; +        HasValidSpec = false; +      } +    if (HasValidSpec) +      SS = Spec;    }    TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; @@ -1539,6 +1550,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,    TypeResult TypeResult = true; // invalid    bool Owned = false; +  Sema::SkipBodyInfo SkipBody;    if (TemplateId) {      // Explicit specialization, class template partial specialization,      // or explicit instantiation. @@ -1625,7 +1637,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,            *TemplateId, attrs.getList(),            MultiTemplateParamsArg(TemplateParams ? &(*TemplateParams)[0]                                                  : nullptr, -                                 TemplateParams ? TemplateParams->size() : 0)); +                                 TemplateParams ? TemplateParams->size() : 0), +          &SkipBody);      }    } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation &&               TUK == Sema::TUK_Declaration) { @@ -1677,6 +1690,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,        TParams =          MultiTemplateParamsArg(&(*TemplateParams)[0], TemplateParams->size()); +    handleDeclspecAlignBeforeClassKey(attrs, DS, TUK); +      // Declaration or definition of a class type      TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,                                         SS, Name, NameLoc, attrs.getList(), AS, @@ -1684,7 +1699,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,                                         TParams, Owned, IsDependent,                                         SourceLocation(), false,                                         clang::TypeResult(), -                                       DSC == DSC_type_specifier); +                                       DSC == DSC_type_specifier, +                                       &SkipBody);      // If ActOnTag said the type was dependent, try again with the      // less common call. @@ -1700,7 +1716,10 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,      assert(Tok.is(tok::l_brace) ||             (getLangOpts().CPlusPlus && Tok.is(tok::colon)) ||             isCXX11FinalKeyword()); -    if (getLangOpts().CPlusPlus) +    if (SkipBody.ShouldSkip) +      SkipCXXMemberSpecification(StartLoc, AttrFixitLoc, TagType, +                                 TagOrTempResult.get()); +    else if (getLangOpts().CPlusPlus)        ParseCXXMemberSpecification(StartLoc, AttrFixitLoc, attrs, TagType,                                    TagOrTempResult.get());      else @@ -1882,51 +1901,40 @@ AccessSpecifier Parser::getAccessSpecifierIfPresent() const {  /// the class definition.  void Parser::HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,                                              Decl *ThisDecl) { -  // We just declared a member function. If this member function -  // has any default arguments or an exception-specification, we'll need to -  // parse them later. -  LateParsedMethodDeclaration *LateMethod = nullptr;    DeclaratorChunk::FunctionTypeInfo &FTI      = DeclaratorInfo.getFunctionTypeInfo(); +  // If there was a late-parsed exception-specification, we'll need a +  // late parse +  bool NeedLateParse = FTI.getExceptionSpecType() == EST_Unparsed; + +  if (!NeedLateParse) { +    // Look ahead to see if there are any default args +    for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) { +      auto Param = cast<ParmVarDecl>(FTI.Params[ParamIdx].Param); +      if (Param->hasUnparsedDefaultArg()) { +        NeedLateParse = true; +        break; +      } +    } +  } -  // If there was a late-parsed exception-specification, hold onto its tokens. -  if (FTI.getExceptionSpecType() == EST_Unparsed) { +  if (NeedLateParse) {      // Push this method onto the stack of late-parsed method      // declarations. -    LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); +    auto LateMethod = new LateParsedMethodDeclaration(this, ThisDecl);      getCurrentClass().LateParsedDeclarations.push_back(LateMethod);      LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); -    // Stash the exception-specification tokens in the late-pased mthod. +    // Stash the exception-specification tokens in the late-pased method.      LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens;      FTI.ExceptionSpecTokens = 0; -    // Reserve space for the parameters. +    // Push tokens for each parameter.  Those that do not have +    // defaults will be NULL.      LateMethod->DefaultArgs.reserve(FTI.NumParams); -  } - -  for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx) { -    if (LateMethod || FTI.Params[ParamIdx].DefaultArgTokens) { -      if (!LateMethod) { -        // Push this method onto the stack of late-parsed method -        // declarations. -        LateMethod = new LateParsedMethodDeclaration(this, ThisDecl); -        getCurrentClass().LateParsedDeclarations.push_back(LateMethod); -        LateMethod->TemplateScope = getCurScope()->isTemplateParamScope(); - -        // Add all of the parameters prior to this one (they don't -        // have default arguments). -        LateMethod->DefaultArgs.reserve(FTI.NumParams); -        for (unsigned I = 0; I < ParamIdx; ++I) -          LateMethod->DefaultArgs.push_back( -              LateParsedDefaultArgument(FTI.Params[I].Param)); -      } - -      // Add this parameter to the list of parameters (it may or may -      // not have a default argument). +    for (unsigned ParamIdx = 0; ParamIdx < FTI.NumParams; ++ParamIdx)        LateMethod->DefaultArgs.push_back(LateParsedDefaultArgument( -          FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens)); -    } +        FTI.Params[ParamIdx].Param, FTI.Params[ParamIdx].DefaultArgTokens));    }  } @@ -2019,7 +2027,7 @@ bool Parser::isCXX11FinalKeyword() const {  /// \brief Parse a C++ member-declarator up to, but not including, the optional  /// brace-or-equal-initializer or pure-specifier. -void Parser::ParseCXXMemberDeclaratorBeforeInitializer( +bool Parser::ParseCXXMemberDeclaratorBeforeInitializer(      Declarator &DeclaratorInfo, VirtSpecifiers &VS, ExprResult &BitfieldSize,      LateParsedAttrList &LateParsedAttrs) {    // member-declarator: @@ -2037,10 +2045,13 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer(      BitfieldSize = ParseConstantExpression();      if (BitfieldSize.isInvalid())        SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); -  } else +  } else {      ParseOptionalCXX11VirtSpecifierSeq(          VS, getCurrentClass().IsInterface,          DeclaratorInfo.getDeclSpec().getFriendSpecLoc()); +    if (!VS.isUnset()) +      MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS); +  }    // If a simple-asm-expr is present, parse it.    if (Tok.is(tok::kw_asm)) { @@ -2071,6 +2082,78 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer(            Diag(Attr->getLoc(), diag::warn_gcc_attribute_location);          Attr = Attr->getNext();        } +      MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq(DeclaratorInfo, VS); +    } +  } + +  // If this has neither a name nor a bit width, something has gone seriously +  // wrong. Skip until the semi-colon or }. +  if (!DeclaratorInfo.hasName() && BitfieldSize.isUnset()) { +    // If so, skip until the semi-colon or a }. +    SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); +    return true; +  } +  return false; +} + +/// \brief Look for declaration specifiers possibly occurring after C++11 +/// virt-specifier-seq and diagnose them. +void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( +    Declarator &D, +    VirtSpecifiers &VS) { +  DeclSpec DS(AttrFactory); + +  // GNU-style and C++11 attributes are not allowed here, but they will be +  // handled by the caller.  Diagnose everything else. +  ParseTypeQualifierListOpt(DS, AR_NoAttributesParsed, false); +  D.ExtendWithDeclSpec(DS); + +  if (D.isFunctionDeclarator()) { +    auto &Function = D.getFunctionTypeInfo(); +    if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) { +      auto DeclSpecCheck = [&] (DeclSpec::TQ TypeQual, +                                const char *FixItName, +                                SourceLocation SpecLoc, +                                unsigned* QualifierLoc) { +        FixItHint Insertion; +        if (DS.getTypeQualifiers() & TypeQual) { +          if (!(Function.TypeQuals & TypeQual)) { +            std::string Name(FixItName); +            Name += " "; +            Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name.c_str()); +            Function.TypeQuals |= TypeQual; +            *QualifierLoc = SpecLoc.getRawEncoding(); +          } +          Diag(SpecLoc, diag::err_declspec_after_virtspec) +            << FixItName +            << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) +            << FixItHint::CreateRemoval(SpecLoc) +            << Insertion; +        } +      }; +      DeclSpecCheck(DeclSpec::TQ_const, "const", DS.getConstSpecLoc(), +                    &Function.ConstQualifierLoc); +      DeclSpecCheck(DeclSpec::TQ_volatile, "volatile", DS.getVolatileSpecLoc(), +                    &Function.VolatileQualifierLoc); +      DeclSpecCheck(DeclSpec::TQ_restrict, "restrict", DS.getRestrictSpecLoc(), +                    &Function.RestrictQualifierLoc); +    } + +    // Parse ref-qualifiers. +    bool RefQualifierIsLValueRef = true; +    SourceLocation RefQualifierLoc; +    if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) { +      const char *Name = (RefQualifierIsLValueRef ? "& " : "&& "); +      FixItHint Insertion = FixItHint::CreateInsertion(VS.getFirstLocation(), Name); +      Function.RefQualifierIsLValueRef = RefQualifierIsLValueRef; +      Function.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); + +      Diag(RefQualifierLoc, diag::err_declspec_after_virtspec) +        << (RefQualifierIsLValueRef ? "&" : "&&") +        << VirtSpecifiers::getSpecifierName(VS.getLastSpecifier()) +        << FixItHint::CreateRemoval(RefQualifierLoc) +        << Insertion; +      D.SetRangeEnd(RefQualifierLoc);      }    }  } @@ -2298,14 +2381,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,    bool ExpectSemi = true;    // Parse the first declarator. -  ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize, -                                            LateParsedAttrs); - -  // If this has neither a name nor a bit width, something has gone seriously -  // wrong. Skip until the semi-colon or }. -  if (!DeclaratorInfo.hasName() && BitfieldSize.isUnset()) { -    // If so, skip until the semi-colon or a }. -    SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); +  if (ParseCXXMemberDeclaratorBeforeInitializer( +          DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) {      TryConsumeToken(tok::semi);      return;    } @@ -2344,6 +2421,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,            DefinitionKind = FDK_Deleted;        }      } +    DeclaratorInfo.setFunctionDefinitionKind(DefinitionKind);      // C++11 [dcl.attr.grammar] p4: If an attribute-specifier-seq appertains       // to a friend declaration, that declaration shall be a definition. @@ -2354,7 +2432,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,        ProhibitAttributes(FnAttrs);      } -    if (DefinitionKind) { +    if (DefinitionKind != FDK_Declaration) {        if (!DeclaratorInfo.isFunctionDeclarator()) {          Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_func_def_no_params);          ConsumeBrace(); @@ -2376,7 +2454,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,        Decl *FunDecl =          ParseCXXInlineMethodDef(AS, AccessAttrs, DeclaratorInfo, TemplateInfo, -                                VS, DefinitionKind, Init); +                                VS, Init);        if (FunDecl) {          for (unsigned i = 0, ni = CommonLateParsedAttrs.size(); i < ni; ++i) { @@ -2530,16 +2608,17 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,      // Parse the next declarator.      DeclaratorInfo.clear();      VS.clear(); -    BitfieldSize = true; -    Init = true; +    BitfieldSize = ExprResult(/*Invalid=*/false); +    Init = ExprResult(/*Invalid=*/false);      HasInitializer = false;      DeclaratorInfo.setCommaLoc(CommaLoc);      // GNU attributes are allowed before the second and subsequent declarator.      MaybeParseGNUAttributes(DeclaratorInfo); -    ParseCXXMemberDeclaratorBeforeInitializer(DeclaratorInfo, VS, BitfieldSize, -                                              LateParsedAttrs); +    if (ParseCXXMemberDeclaratorBeforeInitializer( +            DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) +      break;    }    if (ExpectSemi && @@ -2617,6 +2696,55 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction,    return ParseInitializer();  } +void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc, +                                        SourceLocation AttrFixitLoc, +                                        unsigned TagType, Decl *TagDecl) { +  // Skip the optional 'final' keyword. +  if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { +    assert(isCXX11FinalKeyword() && "not a class definition"); +    ConsumeToken(); + +    // Diagnose any C++11 attributes after 'final' keyword. +    // We deliberately discard these attributes. +    ParsedAttributesWithRange Attrs(AttrFactory); +    CheckMisplacedCXX11Attribute(Attrs, AttrFixitLoc); + +    // This can only happen if we had malformed misplaced attributes; +    // we only get called if there is a colon or left-brace after the +    // attributes. +    if (Tok.isNot(tok::colon) && Tok.isNot(tok::l_brace)) +      return; +  } + +  // Skip the base clauses. This requires actually parsing them, because +  // otherwise we can't be sure where they end (a left brace may appear +  // within a template argument). +  if (Tok.is(tok::colon)) { +    // Enter the scope of the class so that we can correctly parse its bases. +    ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); +    ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true, +                                      TagType == DeclSpec::TST_interface); +    Actions.ActOnTagStartSkippedDefinition(getCurScope(), TagDecl); + +    // Parse the bases but don't attach them to the class. +    ParseBaseClause(nullptr); + +    Actions.ActOnTagFinishSkippedDefinition(); + +    if (!Tok.is(tok::l_brace)) { +      Diag(PP.getLocForEndOfToken(PrevTokLocation), +           diag::err_expected_lbrace_after_base_specifiers); +      return; +    } +  } + +  // Skip the body. +  assert(Tok.is(tok::l_brace)); +  BalancedDelimiterTracker T(*this, tok::l_brace); +  T.consumeOpen(); +  T.skipToEnd(); +} +  /// ParseCXXMemberSpecification - Parse the class definition.  ///  ///       member-specification: @@ -2911,6 +3039,10 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,      ParseLexedMemberInitializers(getCurrentClass());      ParseLexedMethodDefs(getCurrentClass());      PrevTokLocation = SavedPrevTokLocation; + +    // We've finished parsing everything, including default argument +    // initializers. +    Actions.ActOnFinishCXXMemberDefaultArgs(TagDecl);    }    if (TagDecl) @@ -2965,9 +3097,11 @@ void Parser::DiagnoseUnexpectedNamespace(NamedDecl *D) {  ///          mem-initializer ...[opt]  ///          mem-initializer ...[opt] , mem-initializer-list  void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { -  assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); +  assert(Tok.is(tok::colon) && +         "Constructor initializer always starts with ':'"); -  // Poison the SEH identifiers so they are flagged as illegal in constructor initializers +  // Poison the SEH identifiers so they are flagged as illegal in constructor +  // initializers.    PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);    SourceLocation ColonLoc = ConsumeToken(); @@ -3396,7 +3530,9 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) {      // Alternative tokens do not have identifier info, but their spelling      // starts with an alphabetical character.      SmallString<8> SpellingBuf; -    StringRef Spelling = PP.getSpelling(Tok.getLocation(), SpellingBuf); +    SourceLocation SpellingLoc = +        PP.getSourceManager().getSpellingLoc(Tok.getLocation()); +    StringRef Spelling = PP.getSpelling(SpellingLoc, SpellingBuf);      if (isLetter(Spelling[0])) {        Loc = ConsumeToken();        return &PP.getIdentifierTable().get(Spelling); @@ -3474,7 +3610,6 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,          // The attribute was allowed to have arguments, but none were provided          // even though the attribute parsed successfully. This is an error.          Diag(LParenLoc, diag::err_attribute_requires_arguments) << AttrName; -        return false;        } else if (!Attr->getMaxArgs()) {          // The attribute parsed successfully, but was not allowed to have any          // arguments. It doesn't matter whether any were provided -- the @@ -3482,7 +3617,6 @@ bool Parser::ParseCXX11AttributeArgs(IdentifierInfo *AttrName,          Diag(LParenLoc, diag::err_cxx11_attribute_forbids_arguments)              << AttrName              << FixItHint::CreateRemoval(SourceRange(LParenLoc, *EndLoc)); -        return false;        }      }    } | 
