On Wed, May 21, 2014 at 8:57 PM, Justin Bogner <[email protected]>wrote:
> This seems to cause a problem with libc++: > > > http://lab.llvm.org:8013/builders/libcxx_clang-x86_64-darwin11-RA/builds/750 > > All of the erros seem to boil down to the following: > > #include <functional> > struct A { > int foo(int) const { return 1; } > }; > void foo() { > std::function<int(const A*, int)> f = &A::foo; > } > > This no longer compiles. Is it a problem in libc++, or with this change? This is a bug in libc++'s is_function implementation; it doesn't do the right thing for function types with cv-qualifiers or a ref-qualifier. > Richard Smith <[email protected]> writes: > > Author: rsmith > > Date: Wed May 14 18:23:27 2014 > > New Revision: 208825 > > > > URL: http://llvm.org/viewvc/llvm-project?rev=208825&view=revLog: > > PR19742: cv-qualifiers and ref-qualifiers aren't allowed on functions > within > > pointer and reference types, even if those types are produced by template > > instantiation. > > > > Modified: > > cfe/trunk/lib/Sema/SemaType.cpp > > cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp > > cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp > > > > Modified: cfe/trunk/lib/Sema/SemaType.cpp > > URL: > > > http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=208825&r1=208824&r2=208825&view=diff============================================================================== > > --- cfe/trunk/lib/Sema/SemaType.cpp (original) > > +++ cfe/trunk/lib/Sema/SemaType.cpp Wed May 14 18:23:27 2014 > > @@ -1311,6 +1311,59 @@ static QualType inferARCLifetimeForPoint > > return S.Context.getQualifiedType(type, qs); > > } > > > > +static std::string getFunctionQualifiersAsString(const > FunctionProtoType *FnTy){ > > + std::string Quals = > > + Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString(); > > + > > + switch (FnTy->getRefQualifier()) { > > + case RQ_None: > > + break; > > + > > + case RQ_LValue: > > + if (!Quals.empty()) > > + Quals += ' '; > > + Quals += '&'; > > + break; > > + > > + case RQ_RValue: > > + if (!Quals.empty()) > > + Quals += ' '; > > + Quals += "&&"; > > + break; > > + } > > + > > + return Quals; > > +} > > + > > +namespace { > > +/// Kinds of declarator that cannot contain a qualified function type. > > +/// > > +/// C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: > > +/// a function type with a cv-qualifier or a ref-qualifier can only > appear > > +/// at the topmost level of a type. > > +/// > > +/// Parens and member pointers are permitted. We don't diagnose array > and > > +/// function declarators, because they don't allow function types at > all. > > +/// > > +/// The values of this enum are used in diagnostics. > > +enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, > QFK_Reference }; > > +} > > + > > +/// Check whether the type T is a qualified function type, and if it is, > > +/// diagnose that it cannot be contained within the given kind of > declarator. > > +static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation > Loc, > > + QualifiedFunctionKind QFK) { > > + // Does T refer to a function type with a cv-qualifier or a > ref-qualifier? > > + const FunctionProtoType *FPT = T->getAs<FunctionProtoType>(); > > + if (!FPT || (FPT->getTypeQuals() == 0 && FPT->getRefQualifier() == > RQ_None)) > > + return false; > > + > > + S.Diag(Loc, diag::err_compound_qualified_function_type) > > + << QFK << isa<FunctionType>(T.IgnoreParens()) << T > > + << getFunctionQualifiersAsString(FPT); > > + return true; > > +} > > + > > /// \brief Build a pointer type. > > /// > > /// \param T The type to which we'll be building a pointer. > > @@ -1333,6 +1386,9 @@ QualType Sema::BuildPointerType(QualType > > return QualType(); > > } > > > > + if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer)) > > + return QualType(); > > + > > assert(!T->isObjCObjectType() && "Should build > ObjCObjectPointerType"); > > > > // In ARC, it is forbidden to build pointers to unqualified pointers. > > @@ -1392,6 +1448,9 @@ QualType Sema::BuildReferenceType(QualTy > > return QualType(); > > } > > > > + if (checkQualifiedFunction(*this, T, Loc, QFK_Reference)) > > + return QualType(); > > + > > // In ARC, it is forbidden to build references to unqualified > pointers. > > if (getLangOpts().ObjCAutoRefCount) > > T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); > > @@ -1803,6 +1862,9 @@ QualType Sema::BuildBlockPointerType(Qua > > return QualType(); > > } > > > > + if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer)) > > + return QualType(); > > + > > return Context.getBlockPointerType(T); > > } > > > > @@ -2270,66 +2332,6 @@ static QualType GetDeclSpecTypeForDeclar > > return T; > > } > > > > -static std::string getFunctionQualifiersAsString(const > FunctionProtoType *FnTy){ > > - std::string Quals = > > - Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString(); > > - > > - switch (FnTy->getRefQualifier()) { > > - case RQ_None: > > - break; > > - > > - case RQ_LValue: > > - if (!Quals.empty()) > > - Quals += ' '; > > - Quals += '&'; > > - break; > > - > > - case RQ_RValue: > > - if (!Quals.empty()) > > - Quals += ' '; > > - Quals += "&&"; > > - break; > > - } > > - > > - return Quals; > > -} > > - > > -/// Check that the function type T, which has a cv-qualifier or a > ref-qualifier, > > -/// can be contained within the declarator chunk DeclType, and produce > an > > -/// appropriate diagnostic if not. > > -static void checkQualifiedFunction(Sema &S, QualType T, > > - DeclaratorChunk &DeclType) { > > - // C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: a function type with a > > - // cv-qualifier or a ref-qualifier can only appear at the topmost > level > > - // of a type. > > - int DiagKind = -1; > > - switch (DeclType.Kind) { > > - case DeclaratorChunk::Paren: > > - case DeclaratorChunk::MemberPointer: > > - // These cases are permitted. > > - return; > > - case DeclaratorChunk::Array: > > - case DeclaratorChunk::Function: > > - // These cases don't allow function types at all; no need to > diagnose the > > - // qualifiers separately. > > - return; > > - case DeclaratorChunk::BlockPointer: > > - DiagKind = 0; > > - break; > > - case DeclaratorChunk::Pointer: > > - DiagKind = 1; > > - break; > > - case DeclaratorChunk::Reference: > > - DiagKind = 2; > > - break; > > - } > > - > > - assert(DiagKind != -1); > > - S.Diag(DeclType.Loc, diag::err_compound_qualified_function_type) > > - << DiagKind << isa<FunctionType>(T.IgnoreParens()) << T > > - << getFunctionQualifiersAsString(T->castAs<FunctionProtoType>()); > > -} > > - > > /// Produce an appropriate diagnostic for an ambiguity between a > function > > /// declarator and a C++ direct-initializer. > > static void warnAboutAmbiguousFunction(Sema &S, Declarator &D, > > @@ -2546,10 +2548,7 @@ static TypeSourceInfo *GetFullTypeForDec > > unsigned chunkIndex = e - i - 1; > > state.setCurrentChunkIndex(chunkIndex); > > DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex); > > - if (IsQualifiedFunction) { > > - checkQualifiedFunction(S, T, DeclType); > > - IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren; > > - } > > + IsQualifiedFunction &= DeclType.Kind == DeclaratorChunk::Paren; > > switch (DeclType.Kind) { > > case DeclaratorChunk::Paren: > > T = S.BuildParenType(T); > > @@ -3093,6 +3092,13 @@ static TypeSourceInfo *GetFullTypeForDec > > // alias-declaration, > > // - the type-id in the default argument of a type-parameter, or > > // - the type-id of a template-argument for a type-parameter > > + // > > + // FIXME: Checking this here is insufficient. We accept-invalid on: > > + // > > + // template<typename T> struct S { void f(T); }; > > + // S<int() const> s; > > + // > > + // ... for instance. > > if (IsQualifiedFunction && > > !(!FreeFunction && > > D.getDeclSpec().getStorageClassSpec() != > DeclSpec::SCS_static) && > > > > Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp > > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp?rev=208825&r1=208824&r2=208825&view=diff============================================================================== > > --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp (original) > > +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Wed May 14 > 18:23:27 2014 > > @@ -22,13 +22,13 @@ typedef func_type_rvalue &func_type_rval > > > > template<typename T = func_type_lvalue> struct wrap { > > typedef T val; > > - typedef T *ptr; > > - typedef T &ref; > > + typedef T *ptr; // expected-error-re 2{{pointer to function type > '{{.*}}' cannot have '{{&|&&}}' qualifier}} > > + typedef T &ref; // expected-error-re 2{{reference to function type > '{{.*}}' cannot have '{{&|&&}}' qualifier}} > > }; > > > > -using func_type_lvalue = wrap<>::val; > > +using func_type_lvalue = wrap<>::val; // expected-note{{in > instantiation of}} > > using func_type_lvalue = wrap<func_type_lvalue>::val; > > -using func_type_rvalue = wrap<func_type_rvalue>::val; > > +using func_type_rvalue = wrap<func_type_rvalue>::val; // > expected-note{{in instantiation of}} > > > > using func_type_lvalue_ptr = wrap<>::ptr; > > using func_type_lvalue_ptr = wrap<func_type_lvalue>::ptr; > > @@ -51,3 +51,10 @@ void (X::*mpf2)() && = &X::f1; > > > > > > void (f() &&); // expected-error{{non-member function cannot have '&&' > qualifier}} > > + > > +// FIXME: These are ill-formed. > > +template<typename T> struct pass { > > + void f(T); > > +}; > > +pass<func_type_lvalue> pass0; > > +pass<func_type_lvalue> pass1; > > > > Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp > > URL: > http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp?rev=208825&r1=208824&r2=208825&view=diff============================================================================== > > --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp (original) > > +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp Wed May 14 > 18:23:27 2014 > > @@ -18,3 +18,16 @@ struct Y { > > friend void X::f() const; > > friend void ::f() const; // expected-error {{non-member function > cannot have 'const' qualifier}} > > }; > > + > > +template<typename T> struct S { > > + typedef T F; > > + typedef T *P; // expected-error {{pointer to function type 'void () > const' cannot have 'const' qualifier}} > > + typedef T &R; // expected-error {{reference to function type 'void () > const' cannot have 'const' qualifier}} > > +}; > > +S<F> s; // expected-note {{in instantiation of}} > > + > > +// FIXME: This is ill-formed. > > +template<typename T> struct U { > > + void f(T); > > +}; > > +U<F> u; > > > > > > _______________________________________________ > > cfe-commits mailing list > > [email protected] > > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
