r208825 - PR19742: cv-qualifiers and ref-qualifiers aren't allowed on functions within

Justin Bogner mail at justinbogner.com
Wed May 21 20:57:08 PDT 2014


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?

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



More information about the cfe-commits mailing list