[cfe-commits] r122520 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/DeclSpec.h include/clang/Sema/Sema.h lib/Parse/ParseDecl.cpp lib/Parse/ParseTentative.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateVariadic.cpp lib/Sema/SemaType.cpp test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
Douglas Gregor
dgregor at apple.com
Thu Dec 23 14:44:42 PST 2010
Author: dgregor
Date: Thu Dec 23 16:44:42 2010
New Revision: 122520
URL: http://llvm.org/viewvc/llvm-project?rev=122520&view=rev
Log:
Implement parsing of function parameter packs and non-type template
parameter packs (C++0x [dcl.fct]p13), including disambiguation between
unnamed function parameter packs and varargs (C++0x [dcl.fct]p14) for
cases like
void f(T...)
where T may or may not contain unexpanded parameter packs.
Added:
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/DeclSpec.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseTentative.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
cfe/trunk/lib/Sema/SemaType.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Dec 23 16:44:42 2010
@@ -1861,6 +1861,12 @@
"pack expansion contains parameter packs %0 and %1 that have different "
"lengths (%2 vs. %3)">;
+def err_function_parameter_pack_without_parameter_packs : Error<
+ "type %0 of function parameter pack does not contain any unexpanded "
+ "parameter packs">;
+def err_ellipsis_in_declarator_not_parameter : Error<
+ "only function and template parameters can be parameter packs">;
+
// Unsupported variadic templates features
def err_pack_expansion_unsupported : Error<
"clang does not yet support %select{non-type|template}0 pack expansions">;
@@ -1868,6 +1874,10 @@
"clang cannot yet instantiate pack expansions">;
def err_pack_expansion_mismatch_unsupported : Error<
"clang cannot yet instantiate pack expansions with mismatched pack levels">;
+def err_function_parameter_pack_unsupported : Error<
+ "clang does not yet support function parameter packs">;
+def err_non_type_parameter_pack_unsupported : Error<
+ "clang does not yet support non-type template parameter packs">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;
Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Thu Dec 23 16:44:42 2010
@@ -1186,6 +1186,10 @@
/// Extension - true if the declaration is preceded by __extension__.
bool Extension : 1;
+ /// \brief If provided, the source location of the ellipsis used to describe
+ /// this declarator as a parameter pack.
+ SourceLocation EllipsisLoc;
+
friend struct DeclaratorChunk;
public:
@@ -1427,6 +1431,10 @@
void setGroupingParens(bool flag) { GroupingParens = flag; }
bool hasGroupingParens() const { return GroupingParens; }
+
+ bool hasEllipsis() const { return EllipsisLoc.isValid(); }
+ SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+ void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; }
};
/// FieldDeclarator - This little struct is used to capture information about
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Dec 23 16:44:42 2010
@@ -3134,6 +3134,8 @@
const TemplateArgument *Args,
unsigned NumArgs);
+#pragma mark C++ Variadic Templates (C++0x [temp.variadic])
+
/// \brief The context in which an unexpanded parameter pack is
/// being diagnosed.
///
@@ -3325,6 +3327,25 @@
bool &ShouldExpand,
unsigned &NumExpansions);
+ /// \brief Determine whether the given declarator contains any unexpanded
+ /// parameter packs.
+ ///
+ /// This routine is used by the parser to disambiguate function declarators
+ /// with an ellipsis prior to the ')', e.g.,
+ ///
+ /// \code
+ /// void f(T...);
+ /// \endcode
+ ///
+ /// To determine whether we have an (unnamed) function parameter pack or
+ /// a variadic function.
+ ///
+ /// \returns true if the declarator contains any unexpanded parameter packs,
+ /// false otherwise.
+ bool containsUnexpandedParameterPacks(Declarator &D);
+
+#pragma mark C++ Template Argument Deduction (C++ [temp.deduct])
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Dec 23 16:44:42 2010
@@ -2819,7 +2819,7 @@
/// [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 @@
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.
Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Thu Dec 23 16:44:42 2010
@@ -461,6 +461,7 @@
/// abstract-declarator:
/// ptr-operator abstract-declarator[opt]
/// direct-abstract-declarator
+/// ...
///
/// direct-abstract-declarator:
/// direct-abstract-declarator[opt]
@@ -483,7 +484,7 @@
/// 'volatile'
///
/// declarator-id:
-/// id-expression
+/// '...'[opt] id-expression
///
/// id-expression:
/// unqualified-id
@@ -522,7 +523,9 @@
// 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 @@
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 @@
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();
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Dec 23 16:44:42 2010
@@ -4959,20 +4959,34 @@
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 @@
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)
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Dec 23 16:44:42 2010
@@ -632,6 +632,12 @@
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(),
Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Thu Dec 23 16:44:42 2010
@@ -413,3 +413,72 @@
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;
+}
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=122520&r1=122519&r2=122520&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Thu Dec 23 16:44:42 2010
@@ -1465,6 +1465,64 @@
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 @@
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();
Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp?rev=122520&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p13.cpp Thu Dec 23 16:44:42 2010
@@ -0,0 +1,48 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fexceptions -verify %s
+
+// When it is part of a parameter-declaration-clause, the parameter
+// pack is a function parameter pack.
+template<typename ...Types>
+void f0(Types ...args); // FIXME: temporary expected-error{{clang does not yet support function parameter packs}}
+
+template<typename ...Types>
+void f1(const Types &...args); // FIXME: temporary expected-error{{clang does not yet support function parameter packs}}
+
+// [ Note: Otherwise, the parameter-declaration is part of a
+// template-parameter-list and the parameter pack is a template
+// parameter pack; see 14.1. -- end note ]
+template<int ...N> // FIXME: temporary expected-error{{clang does not yet support non-type template parameter packs}}
+struct X0 { };
+
+template<typename ...Types>
+struct X1 {
+ template<Types ...Values> struct Inner; // FIXME: temporary expected-error{{clang does not yet support non-type template parameter packs}}
+};
+
+// A declarator-id or abstract-declarator containing an ellipsis shall
+// only be used in a parameter-declaration.
+int (...f2)(int); // expected-error{{only function and template parameters can be parameter packs}}
+
+void f3() {
+ int ...x; // expected-error{{only function and template parameters can be parameter packs}}
+ if (int ...y = 17) { } // expected-error{{only function and template parameters can be parameter packs}}
+
+ for (int ...z = 0; z < 10; ++z) { } // expected-error{{only function and template parameters can be parameter packs}}
+
+ try {
+ } catch (int ...e) { // expected-error{{only function and template parameters can be parameter packs}}
+ }
+}
+
+template<typename ...Types>
+struct X2 {
+ Types ...members; // expected-error{{only function and template parameters can be parameter packs}} \
+ // expected-error{{data member type contains unexpanded parameter pack}}
+};
+
+// 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.
+template<typename T>
+void f4(T ...args); // expected-error{{type 'T' of function parameter pack does not contain any unexpanded parameter packs}}
+
Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp?rev=122520&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p14.cpp Thu Dec 23 16:44:42 2010
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T> struct identity;
+template<typename ...Types> struct tuple;
+
+template<typename T, typename U> struct is_same {
+ static const bool value = false;
+};
+
+template<typename T> struct is_same<T, T> {
+ static const bool value = true;
+};
+
+// 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.
+
+template<typename T, typename ...Types>
+struct X0 {
+ typedef identity<T(Types...)> function_pack_1; // expected-error{{clang does not yet support function parameter packs}}
+ typedef identity<T(Types......)> variadic_function_pack_1; // expected-error{{clang does not yet support function parameter packs}}
+ typedef identity<T(T...)> variadic_1;
+ typedef tuple<T(Types, ...)...> template_arg_expansion_1;
+};
+
+
+
+// FIXME: Once function parameter packs are implemented, we can test all of the disambiguation
More information about the cfe-commits
mailing list