diff options
author | Douglas Gregor <dgregor@apple.com> | 2010-12-16 00:46:58 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2010-12-16 00:46:58 +0000 |
commit | 56c04588ef3cfa1bbc968fd68de2480a4e66971d (patch) | |
tree | a173c0b5da0ca60b5b2d40d7e8eb49674e7fac27 | |
parent | 0c9e4799fd78d350a037498b2c797f2b2558791c (diff) |
Check for unexpanded parameter packs in using declarations. As a
drive-by, make sure to check for unexpanded parameter packs within the
name of a declaration.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121930 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 12 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 25 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 52 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.variadic/p5.cpp | 9 |
6 files changed, 97 insertions, 9 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f6e6f075b6..e9617a2f11 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1823,19 +1823,23 @@ def note_template_parameter_pack_here : Note< def err_unexpanded_parameter_pack_0 : Error< "%select{expression|base type|declaration type|data member type|bit-field " - "size|static assertion|fixed underlying type|enumerator value}0 " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration}0 " "contains an unexpanded parameter pack">; def err_unexpanded_parameter_pack_1 : Error< "%select{expression|base type|declaration type|data member type|bit-field " - "size|static assertion|fixed underlying type|enumerator value}0 " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration}0 " "contains unexpanded parameter pack %1">; def err_unexpanded_parameter_pack_2 : Error< "%select{expression|base type|declaration type|data member type|bit-field " - "size|static assertion|fixed underlying type|enumerator value}0 " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration}0 " "contains unexpanded parameter packs %1 and %2">; def err_unexpanded_parameter_pack_3_or_more : Error< "%select{expression|base type|declaration type|data member type|bit-field " - "size|static assertion|fixed underlying type|enumerator value}0 " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration}0 " "contains unexpanded parameter packs %1, %2, ...">; def err_unexpected_typedef : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index c375b84808..c48f40403c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3157,7 +3157,10 @@ public: UPPC_FixedUnderlyingType, /// \brief The enumerator value. - UPPC_EnumeratorValue + UPPC_EnumeratorValue, + + /// \brief A using declaration. + UPPC_UsingDeclaration }; /// \brief If the given type contains an unexpanded parameter pack, @@ -3182,6 +3185,26 @@ public: bool DiagnoseUnexpandedParameterPack(Expr *E, UnexpandedParameterPackContext UPPC = UPPC_Expression); + /// \brief If the given nested-name-specifier contains an unexpanded + /// parameter pack, diagnose the error. + /// + /// \param SS The nested-name-specifier that is being checked for + /// unexpanded parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param NameInfo The name (with source location information) that + /// is being checked for unexpanded parameter packs. + /// + /// \returns true if an error ocurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, + UnexpandedParameterPackContext UPPC); + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 95c3b99801..c3384a5162 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2319,7 +2319,8 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, diag::err_declarator_need_ident) << D.getDeclSpec().getSourceRange() << D.getSourceRange(); return 0; - } + } else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType)) + return 0; // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 555f5fd424..4a9abec583 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -928,6 +928,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } // FIXME: Check for template parameters! + // FIXME: Check that the name is an identifier! Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, AS); assert(Member && "HandleField never returns null"); @@ -3547,6 +3548,10 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); } + if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || + DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) + return 0; + NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, TargetNameInfo, AttrList, /* IsInstantiation */ false, diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 057792914b..2338b5bfbc 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -171,7 +171,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, } bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, - UnexpandedParameterPackContext UPPC) { + UnexpandedParameterPackContext UPPC) { // C++0x [temp.variadic]p5: // An appearance of a name of a parameter pack that is not expanded is // ill-formed. @@ -184,3 +184,53 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E, DiagnoseUnexpandedParameterPacks(*this, E->getLocStart(), UPPC, Unexpanded); return true; } + +bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, + UnexpandedParameterPackContext UPPC) { + // C++0x [temp.variadic]p5: + // An appearance of a name of a parameter pack that is not expanded is + // ill-formed. + if (!SS.getScopeRep() || + !SS.getScopeRep()->containsUnexpandedParameterPack()) + return false; + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseNestedNameSpecifier(SS.getScopeRep()); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, SS.getRange().getBegin(), + UPPC, Unexpanded); + return true; +} + +bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, + UnexpandedParameterPackContext UPPC) { + // C++0x [temp.variadic]p5: + // An appearance of a name of a parameter pack that is not expanded is + // ill-formed. + switch (NameInfo.getName().getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + return false; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (!NameInfo.getNamedTypeInfo()->getType() + ->containsUnexpandedParameterPack()) + return false; + break; + } + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseTypeLoc(NameInfo.getNamedTypeInfo()->getTypeLoc()); + assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs"); + DiagnoseUnexpandedParameterPacks(*this, NameInfo.getLoc(), UPPC, Unexpanded); + return true; +} diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 1f56c889a6..a1c07c96fe 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -104,10 +104,11 @@ void TestPPNameFunc(int i) { } // FIXME: Test for unexpanded parameter packs in declarations. -template<typename... Types> -struct TestUnexpandedDecls { +template<typename T, typename... Types> +struct TestUnexpandedDecls : T{ void member_function(Types); // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} void member_function () throw(Types); // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} + operator Types() const; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} Types data_member; // expected-error{{data member type contains unexpanded parameter pack 'Types'}} static Types static_data_member; // expected-error{{declaration type contains unexpanded parameter pack 'Types'}} unsigned bit_field : static_cast<Types>(0); // expected-error{{bit-field size contains unexpanded parameter pack 'Types'}} @@ -116,6 +117,10 @@ struct TestUnexpandedDecls { enum E0 : Types { // expected-error{{fixed underlying type contains unexpanded parameter pack 'Types'}} EnumValue = static_cast<Types>(0) // expected-error{{enumerator value contains unexpanded parameter pack 'Types'}} }; + + using typename Types::type; // expected-error{{using declaration contains unexpanded parameter pack 'Types'}} + using Types::value; // expected-error{{using declaration contains unexpanded parameter pack 'Types'}} + using T::operator Types; // expected-error{{using declaration contains unexpanded parameter pack 'Types'}} }; // Test for diagnostics in the presence of multiple unexpanded |