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