<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, May 21, 2014 at 8:57 PM, Justin Bogner <span dir="ltr"><<a href="mailto:mail@justinbogner.com" target="_blank">mail@justinbogner.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">This seems to cause a problem with libc++:<br>
<br>
  <a href="http://lab.llvm.org:8013/builders/libcxx_clang-x86_64-darwin11-RA/builds/750" target="_blank">http://lab.llvm.org:8013/builders/libcxx_clang-x86_64-darwin11-RA/builds/750</a><br>
<br>
All of the erros seem to boil down to the following:<br>
<br>
  #include <functional><br>
  struct A {<br>
      int foo(int) const { return 1; }<br>
  };<br>
  void foo() {<br>
      std::function<int(const A*, int)> f = &A::foo;<br>
  }<br>
<br>
This no longer compiles. Is it a problem in libc++, or with this change?</blockquote><div><br></div><div>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.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class=""><div class="h5">
Richard Smith <<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>> writes:<br>
> Author: rsmith<br>
> Date: Wed May 14 18:23:27 2014<br>
> New Revision: 208825<br>
><br>
> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=208825&view=revLog" target="_blank">http://llvm.org/viewvc/llvm-project?rev=208825&view=revLog</a>:<br>
> PR19742: cv-qualifiers and ref-qualifiers aren't allowed on functions within<br>
> pointer and reference types, even if those types are produced by template<br>
> instantiation.<br>
><br>
> Modified:<br>
>     cfe/trunk/lib/Sema/SemaType.cpp<br>
>     cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp<br>
>     cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp<br>
><br>
> Modified: cfe/trunk/lib/Sema/SemaType.cpp<br>
> URL:<br>
> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=208825&r1=208824&r2=208825&view=diff==============================================================================" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=208825&r1=208824&r2=208825&view=diff==============================================================================</a><br>

> --- cfe/trunk/lib/Sema/SemaType.cpp (original)<br>
> +++ cfe/trunk/lib/Sema/SemaType.cpp Wed May 14 18:23:27 2014<br>
> @@ -1311,6 +1311,59 @@ static QualType inferARCLifetimeForPoint<br>
>    return S.Context.getQualifiedType(type, qs);<br>
>  }<br>
><br>
> +static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){<br>
> +  std::string Quals =<br>
> +    Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString();<br>
> +<br>
> +  switch (FnTy->getRefQualifier()) {<br>
> +  case RQ_None:<br>
> +    break;<br>
> +<br>
> +  case RQ_LValue:<br>
> +    if (!Quals.empty())<br>
> +      Quals += ' ';<br>
> +    Quals += '&';<br>
> +    break;<br>
> +<br>
> +  case RQ_RValue:<br>
> +    if (!Quals.empty())<br>
> +      Quals += ' ';<br>
> +    Quals += "&&";<br>
> +    break;<br>
> +  }<br>
> +<br>
> +  return Quals;<br>
> +}<br>
> +<br>
> +namespace {<br>
> +/// Kinds of declarator that cannot contain a qualified function type.<br>
> +///<br>
> +/// C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6:<br>
> +///     a function type with a cv-qualifier or a ref-qualifier can only appear<br>
> +///     at the topmost level of a type.<br>
> +///<br>
> +/// Parens and member pointers are permitted. We don't diagnose array and<br>
> +/// function declarators, because they don't allow function types at all.<br>
> +///<br>
> +/// The values of this enum are used in diagnostics.<br>
> +enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, QFK_Reference };<br>
> +}<br>
> +<br>
> +/// Check whether the type T is a qualified function type, and if it is,<br>
> +/// diagnose that it cannot be contained within the given kind of declarator.<br>
> +static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc,<br>
> +                                   QualifiedFunctionKind QFK) {<br>
> +  // Does T refer to a function type with a cv-qualifier or a ref-qualifier?<br>
> +  const FunctionProtoType *FPT = T->getAs<FunctionProtoType>();<br>
> +  if (!FPT || (FPT->getTypeQuals() == 0 && FPT->getRefQualifier() == RQ_None))<br>
> +    return false;<br>
> +<br>
> +  S.Diag(Loc, diag::err_compound_qualified_function_type)<br>
> +    << QFK << isa<FunctionType>(T.IgnoreParens()) << T<br>
> +    << getFunctionQualifiersAsString(FPT);<br>
> +  return true;<br>
> +}<br>
> +<br>
>  /// \brief Build a pointer type.<br>
>  ///<br>
>  /// \param T The type to which we'll be building a pointer.<br>
> @@ -1333,6 +1386,9 @@ QualType Sema::BuildPointerType(QualType<br>
>      return QualType();<br>
>    }<br>
><br>
> +  if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer))<br>
> +    return QualType();<br>
> +<br>
>    assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType");<br>
><br>
>    // In ARC, it is forbidden to build pointers to unqualified pointers.<br>
> @@ -1392,6 +1448,9 @@ QualType Sema::BuildReferenceType(QualTy<br>
>      return QualType();<br>
>    }<br>
><br>
> +  if (checkQualifiedFunction(*this, T, Loc, QFK_Reference))<br>
> +    return QualType();<br>
> +<br>
>    // In ARC, it is forbidden to build references to unqualified pointers.<br>
>    if (getLangOpts().ObjCAutoRefCount)<br>
>      T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true);<br>
> @@ -1803,6 +1862,9 @@ QualType Sema::BuildBlockPointerType(Qua<br>
>      return QualType();<br>
>    }<br>
><br>
> +  if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer))<br>
> +    return QualType();<br>
> +<br>
>    return Context.getBlockPointerType(T);<br>
>  }<br>
><br>
> @@ -2270,66 +2332,6 @@ static QualType GetDeclSpecTypeForDeclar<br>
>    return T;<br>
>  }<br>
><br>
> -static std::string getFunctionQualifiersAsString(const FunctionProtoType *FnTy){<br>
> -  std::string Quals =<br>
> -    Qualifiers::fromCVRMask(FnTy->getTypeQuals()).getAsString();<br>
> -<br>
> -  switch (FnTy->getRefQualifier()) {<br>
> -  case RQ_None:<br>
> -    break;<br>
> -<br>
> -  case RQ_LValue:<br>
> -    if (!Quals.empty())<br>
> -      Quals += ' ';<br>
> -    Quals += '&';<br>
> -    break;<br>
> -<br>
> -  case RQ_RValue:<br>
> -    if (!Quals.empty())<br>
> -      Quals += ' ';<br>
> -    Quals += "&&";<br>
> -    break;<br>
> -  }<br>
> -<br>
> -  return Quals;<br>
> -}<br>
> -<br>
> -/// Check that the function type T, which has a cv-qualifier or a ref-qualifier,<br>
> -/// can be contained within the declarator chunk DeclType, and produce an<br>
> -/// appropriate diagnostic if not.<br>
> -static void checkQualifiedFunction(Sema &S, QualType T,<br>
> -                                   DeclaratorChunk &DeclType) {<br>
> -  // C++98 [dcl.fct]p4 / C++11 [dcl.fct]p6: a function type with a<br>
> -  // cv-qualifier or a ref-qualifier can only appear at the topmost level<br>
> -  // of a type.<br>
> -  int DiagKind = -1;<br>
> -  switch (DeclType.Kind) {<br>
> -  case DeclaratorChunk::Paren:<br>
> -  case DeclaratorChunk::MemberPointer:<br>
> -    // These cases are permitted.<br>
> -    return;<br>
> -  case DeclaratorChunk::Array:<br>
> -  case DeclaratorChunk::Function:<br>
> -    // These cases don't allow function types at all; no need to diagnose the<br>
> -    // qualifiers separately.<br>
> -    return;<br>
> -  case DeclaratorChunk::BlockPointer:<br>
> -    DiagKind = 0;<br>
> -    break;<br>
> -  case DeclaratorChunk::Pointer:<br>
> -    DiagKind = 1;<br>
> -    break;<br>
> -  case DeclaratorChunk::Reference:<br>
> -    DiagKind = 2;<br>
> -    break;<br>
> -  }<br>
> -<br>
> -  assert(DiagKind != -1);<br>
> -  S.Diag(DeclType.Loc, diag::err_compound_qualified_function_type)<br>
> -    << DiagKind << isa<FunctionType>(T.IgnoreParens()) << T<br>
> -    << getFunctionQualifiersAsString(T->castAs<FunctionProtoType>());<br>
> -}<br>
> -<br>
>  /// Produce an appropriate diagnostic for an ambiguity between a function<br>
>  /// declarator and a C++ direct-initializer.<br>
>  static void warnAboutAmbiguousFunction(Sema &S, Declarator &D,<br>
> @@ -2546,10 +2548,7 @@ static TypeSourceInfo *GetFullTypeForDec<br>
>      unsigned chunkIndex = e - i - 1;<br>
>      state.setCurrentChunkIndex(chunkIndex);<br>
>      DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);<br>
> -    if (IsQualifiedFunction) {<br>
> -      checkQualifiedFunction(S, T, DeclType);<br>
> -      IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren;<br>
> -    }<br>
> +    IsQualifiedFunction &= DeclType.Kind == DeclaratorChunk::Paren;<br>
>      switch (DeclType.Kind) {<br>
>      case DeclaratorChunk::Paren:<br>
>        T = S.BuildParenType(T);<br>
> @@ -3093,6 +3092,13 @@ static TypeSourceInfo *GetFullTypeForDec<br>
>      //    alias-declaration,<br>
>      //  - the type-id in the default argument of a type-parameter, or<br>
>      //  - the type-id of a template-argument for a type-parameter<br>
> +    //<br>
> +    // FIXME: Checking this here is insufficient. We accept-invalid on:<br>
> +    //<br>
> +    //   template<typename T> struct S { void f(T); };<br>
> +    //   S<int() const> s;<br>
> +    //<br>
> +    // ... for instance.<br>
>      if (IsQualifiedFunction &&<br>
>          !(!FreeFunction &&<br>
>            D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&<br>
><br>
> Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp<br>
> URL: <a href="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==============================================================================" target="_blank">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==============================================================================</a><br>

> --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp (original)<br>
> +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp Wed May 14 18:23:27 2014<br>
> @@ -22,13 +22,13 @@ typedef func_type_rvalue &func_type_rval<br>
><br>
>  template<typename T = func_type_lvalue> struct wrap {<br>
>    typedef T val;<br>
> -  typedef T *ptr;<br>
> -  typedef T &ref;<br>
> +  typedef T *ptr; // expected-error-re 2{{pointer to function type '{{.*}}' cannot have '{{&|&&}}' qualifier}}<br>
> +  typedef T &ref; // expected-error-re 2{{reference to function type '{{.*}}' cannot have '{{&|&&}}' qualifier}}<br>
>  };<br>
><br>
> -using func_type_lvalue = wrap<>::val;<br>
> +using func_type_lvalue = wrap<>::val; // expected-note{{in instantiation of}}<br>
>  using func_type_lvalue = wrap<func_type_lvalue>::val;<br>
> -using func_type_rvalue = wrap<func_type_rvalue>::val;<br>
> +using func_type_rvalue = wrap<func_type_rvalue>::val; // expected-note{{in instantiation of}}<br>
><br>
>  using func_type_lvalue_ptr = wrap<>::ptr;<br>
>  using func_type_lvalue_ptr = wrap<func_type_lvalue>::ptr;<br>
> @@ -51,3 +51,10 @@ void (X::*mpf2)() && = &X::f1;<br>
><br>
><br>
>  void (f() &&); // expected-error{{non-member function cannot have '&&' qualifier}}<br>
> +<br>
> +// FIXME: These are ill-formed.<br>
> +template<typename T> struct pass {<br>
> +  void f(T);<br>
> +};<br>
> +pass<func_type_lvalue> pass0;<br>
> +pass<func_type_lvalue> pass1;<br>
><br>
> Modified: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp<br>
> URL: <a href="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==============================================================================" target="_blank">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==============================================================================</a><br>

> --- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp (original)<br>
> +++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6.cpp Wed May 14 18:23:27 2014<br>
> @@ -18,3 +18,16 @@ struct Y {<br>
>    friend void X::f() const;<br>
>    friend void ::f() const; // expected-error {{non-member function cannot have 'const' qualifier}}<br>
>  };<br>
> +<br>
> +template<typename T> struct S {<br>
> +  typedef T F;<br>
> +  typedef T *P; // expected-error {{pointer to function type 'void () const' cannot have 'const' qualifier}}<br>
> +  typedef T &R; // expected-error {{reference to function type 'void () const' cannot have 'const' qualifier}}<br>
> +};<br>
> +S<F> s; // expected-note {{in instantiation of}}<br>
> +<br>
> +// FIXME: This is ill-formed.<br>
> +template<typename T> struct U {<br>
> +  void f(T);<br>
> +};<br>
> +U<F> u;<br>
><br>
><br>
> _______________________________________________<br>
> cfe-commits mailing list<br>
> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</div></div></blockquote></div><br></div></div>