diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 17 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 69 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 64 |
6 files changed, 190 insertions, 22 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 53cccc0819..f627b2c9f4 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2819,7 +2819,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, /// [C++] declarator-id /// /// declarator-id: [C++ 8] -/// id-expression +/// '...'[opt] id-expression /// '::'[opt] nested-name-specifier[opt] type-name /// /// id-expression: [C++ 5.1] @@ -2849,6 +2849,21 @@ void Parser::ParseDirectDeclarator(Declarator &D) { DeclScopeObj.EnterDeclaratorScope(); } + // C++0x [dcl.fct]p14: + // There is a syntactic ambiguity when an ellipsis occurs at the end + // of a parameter-declaration-clause without a preceding comma. In + // this case, the ellipsis is parsed as part of the + // abstract-declarator if the type of the parameter names a template + // parameter pack that has not been expanded; otherwise, it is parsed + // as part of the parameter-declaration-clause. + if (Tok.is(tok::ellipsis) && + !((D.getContext() == Declarator::PrototypeContext || + D.getContext() == Declarator::BlockLiteralContext) && + getCurScope()->getTemplateParamParent() && + NextToken().is(tok::r_paren) && + !Actions.containsUnexpandedParameterPacks(D))) + D.setEllipsisLoc(ConsumeToken()); + 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. diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 81abdb884a..fc57b4086b 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -461,6 +461,7 @@ bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, /// abstract-declarator: /// ptr-operator abstract-declarator[opt] /// direct-abstract-declarator +/// ... /// /// direct-abstract-declarator: /// direct-abstract-declarator[opt] @@ -483,7 +484,7 @@ bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing, /// 'volatile' /// /// declarator-id: -/// id-expression +/// '...'[opt] id-expression /// /// id-expression: /// unqualified-id @@ -522,7 +523,9 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // direct-declarator: // direct-abstract-declarator: - + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + if ((Tok.is(tok::identifier) || (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) && mayHaveIdentifier) { @@ -566,6 +569,10 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, while (1) { TPResult TPR(TPResult::Ambiguous()); + // abstract-declarator: ... + if (Tok.is(tok::ellipsis)) + ConsumeToken(); + if (Tok.is(tok::l_paren)) { // Check whether we have a function declarator or a possible ctor-style // initializer that follows the declarator. Note that ctor-style @@ -1165,8 +1172,8 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { if (Tok.is(tok::equal)) { // '=' assignment-expression // Parse through assignment-expression. - tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren }; - if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/)) + tok::TokenKind StopToks[2] ={ tok::comma, tok::r_paren }; + if (!SkipUntil(StopToks, 2, true/*StopAtSemi*/, true/*DontConsume*/)) return TPResult::Error(); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 890399c428..d596649479 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4959,20 +4959,34 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DiagnoseFunctionSpecifiers(D); - // Check that there are no default arguments inside the type of this - // parameter (C++ only). - if (getLangOptions().CPlusPlus) - CheckExtraCXXDefaultArguments(D); - TagDecl *OwnedDecl = 0; TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S, &OwnedDecl); QualType parmDeclType = TInfo->getType(); - if (getLangOptions().CPlusPlus && OwnedDecl && OwnedDecl->isDefinition()) { - // C++ [dcl.fct]p6: - // Types shall not be defined in return or parameter types. - Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) - << Context.getTypeDeclType(OwnedDecl); + if (getLangOptions().CPlusPlus) { + // Check that there are no default arguments inside the type of this + // parameter. + CheckExtraCXXDefaultArguments(D); + + if (OwnedDecl && OwnedDecl->isDefinition()) { + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + Diag(OwnedDecl->getLocation(), diag::err_type_defined_in_param_type) + << Context.getTypeDeclType(OwnedDecl); + } + + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). + if (D.getCXXScopeSpec().isSet()) { + Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) + << D.getCXXScopeSpec().getRange(); + D.getCXXScopeSpec().clear(); + } + + // FIXME: Variadic templates. + if (D.hasEllipsis()) { + Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_unsupported); + D.setInvalidType(); + } } // Ensure we have a valid name @@ -5021,13 +5035,6 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.isInvalidType()) New->setInvalidDecl(); - // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). - if (D.getCXXScopeSpec().isSet()) { - Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) - << D.getCXXScopeSpec().getRange(); - New->setInvalidDecl(); - } - // Add the parameter declaration into this scope. S->AddDecl(New); if (II) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 1f3e2ef9c8..7357e94490 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -632,6 +632,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, Invalid = true; } + if (D.hasEllipsis()) { + // FIXME: Variadic templates. + Diag(D.getEllipsisLoc(), diag::err_non_type_parameter_pack_unsupported); + Invalid = true; + } + NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), D.getIdentifierLoc(), diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index bb9c01afad..d9c7e72a86 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -413,3 +413,72 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, return false; } + +bool Sema::containsUnexpandedParameterPacks(Declarator &D) { + const DeclSpec &DS = D.getDeclSpec(); + switch (DS.getTypeSpecType()) { + case TST_typename: + case TST_typeofType: { + QualType T = DS.getRepAsType().get(); + if (!T.isNull() && T->containsUnexpandedParameterPack()) + return true; + break; + } + + case TST_typeofExpr: + case TST_decltype: + if (DS.getRepAsExpr() && + DS.getRepAsExpr()->containsUnexpandedParameterPack()) + return true; + break; + + case TST_unspecified: + case TST_void: + case TST_char: + case TST_wchar: + case TST_char16: + case TST_char32: + case TST_int: + case TST_float: + case TST_double: + case TST_bool: + case TST_decimal32: + case TST_decimal64: + case TST_decimal128: + case TST_enum: + case TST_union: + case TST_struct: + case TST_class: + case TST_auto: + case TST_error: + break; + } + + for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) { + const DeclaratorChunk &Chunk = D.getTypeObject(I); + switch (Chunk.Kind) { + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Paren: + // These declarator chunks cannot contain any parameter packs. + break; + + case DeclaratorChunk::Array: + case DeclaratorChunk::Function: + case DeclaratorChunk::BlockPointer: + // Syntactically, these kinds of declarator chunks all come after the + // declarator-id (conceptually), so the parser should not invoke this + // routine at this time. + llvm_unreachable("Could not have seen this kind of declarator chunk"); + break; + + case DeclaratorChunk::MemberPointer: + if (Chunk.Mem.Scope().getScopeRep() && + Chunk.Mem.Scope().getScopeRep()->containsUnexpandedParameterPack()) + return true; + break; + } + } + + return false; +} diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 09b187b0d0..e693c8d4da 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1465,6 +1465,64 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, T.addConst(); } + // If there was an ellipsis in the declarator, the declaration declares a + // parameter pack whose type may be a pack expansion type. + if (D.hasEllipsis() && !T.isNull()) { + // C++0x [dcl.fct]p13: + // A declarator-id or abstract-declarator containing an ellipsis shall + // only be used in a parameter-declaration. Such a parameter-declaration + // is a parameter pack (14.5.3). [...] + switch (D.getContext()) { + case Declarator::PrototypeContext: + // C++0x [dcl.fct]p13: + // [...] When it is part of a parameter-declaration-clause, the + // parameter pack is a function parameter pack (14.5.3). The type T + // of the declarator-id of the function parameter pack shall contain + // a template parameter pack; each template parameter pack in T is + // expanded by the function parameter pack. + // + // We represent function parameter packs as function parameters whose + // type is a pack expansion. + if (!T->containsUnexpandedParameterPack()) { + Diag(D.getEllipsisLoc(), + diag::err_function_parameter_pack_without_parameter_packs) + << T << D.getSourceRange(); + D.setEllipsisLoc(SourceLocation()); + } else { + T = Context.getPackExpansionType(T); + } + break; + + case Declarator::TemplateParamContext: + // C++0x [temp.param]p15: + // If a template-parameter is a [...] is a parameter-declaration that + // declares a parameter pack (8.3.5), then the template-parameter is a + // template parameter pack (14.5.3). + // + // Note: core issue 778 clarifies that, if there are any unexpanded + // parameter packs in the type of the non-type template parameter, then + // it expands those parameter packs. + if (T->containsUnexpandedParameterPack()) + T = Context.getPackExpansionType(T); + break; + + case Declarator::FileContext: + case Declarator::KNRTypeListContext: + case Declarator::TypeNameContext: + case Declarator::MemberContext: + case Declarator::BlockContext: + case Declarator::ForContext: + case Declarator::ConditionContext: + case Declarator::CXXCatchContext: + case Declarator::BlockLiteralContext: + // FIXME: We may want to allow parameter packs in block-literal contexts + // in the future. + Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter); + D.setEllipsisLoc(SourceLocation()); + break; + } + } + // Process any function attributes we might have delayed from the // declaration-specifiers. ProcessDelayedFnAttrs(*this, T, FnAttrsFromDeclSpec); @@ -1729,6 +1787,12 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *TInfo = Context.CreateTypeSourceInfo(T); UnqualTypeLoc CurrTL = TInfo->getTypeLoc().getUnqualifiedLoc(); + // Handle parameter packs whose type is a pack expansion. + if (isa<PackExpansionType>(T)) { + cast<PackExpansionTypeLoc>(CurrTL).setEllipsisLoc(D.getEllipsisLoc()); + CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); + } + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); |