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