r208825 - PR19742: cv-qualifiers and ref-qualifiers aren't allowed on functions within
Richard Smith
richard at metafoo.co.uk
Thu May 22 11:54:48 PDT 2014
On Wed, May 21, 2014 at 8:57 PM, Justin Bogner <mail at justinbogner.com>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 <richard-llvm at metafoo.co.uk> 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
> > cfe-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140522/9a77826a/attachment.html>
More information about the cfe-commits
mailing list