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

Richard Smith richard-llvm at metafoo.co.uk
Wed May 14 16:23:27 PDT 2014


Author: rsmith
Date: Wed May 14 18:23:27 2014
New Revision: 208825

URL: http://llvm.org/viewvc/llvm-project?rev=208825&view=rev
Log:
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;





More information about the cfe-commits mailing list