[cfe-commits] r150244 - in /cfe/trunk: include/clang/Basic/ lib/Parse/ lib/Sema/ test/CXX/class/class.friend/ test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/ test/CXX/dcl.dcl/dcl.spec/dcl.typedef/ test/CXX/dcl.decl/dcl.meaning/dcl.fct/ test/FixIt/ test/SemaCXX/

Richard Smith richard-llvm at metafoo.co.uk
Fri Feb 10 03:05:11 PST 2012


Author: rsmith
Date: Fri Feb 10 05:05:11 2012
New Revision: 150244

URL: http://llvm.org/viewvc/llvm-project?rev=150244&view=rev
Log:
PR11684, core issue 1417:

o Correct the handling of the restrictions on usage of cv-qualified and
  ref-qualified function types.
o Fix a bug where such types were rejected in template type parameter default
  arguments, due to such arguments not being treated as a template type arg
  context.
o Remove the ExtWarn for usage of such types as template arguments; that was
  a standard defect, not a GCC extension.
o Improve the wording and unify the code for diagnosing cv-qualifiers with the
  code for diagnosing ref-qualifiers.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/class/class.friend/p1.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.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
    cfe/trunk/test/FixIt/fixit.cpp
    cfe/trunk/test/SemaCXX/alias-template.cpp
    cfe/trunk/test/SemaCXX/destructor.cpp
    cfe/trunk/test/SemaCXX/function-type-qual.cpp
    cfe/trunk/test/SemaCXX/issue547.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Feb 10 05:05:11 2012
@@ -3720,22 +3720,11 @@
 def err_invalid_member_use_in_static_method : Error<
   "invalid use of member %0 in static member function">;
 def err_invalid_qualified_function_type : Error<
-  "type qualifier is not allowed on this function">;
-def err_invalid_ref_qualifier_function_type : Error<
-  "ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions,"
-  " member function pointers, and typedefs of function types">;
-def ext_qualified_function_type_template_arg : ExtWarn<
-  "template argument of '%0' qualified function type is a GNU extension">, 
-  InGroup<GNU>;
-
-def err_invalid_qualified_function_pointer : Error<
-  "type qualifier is not allowed on this function %select{pointer|reference}0">;
-def err_invalid_qualified_typedef_function_type_use : Error<
-  "a qualified function type cannot be used to declare a "
-  "%select{static member|nonmember}0 function">;
-def err_invalid_ref_qualifier_typedef_function_type_use : Error<
-  "%select{static member|nonmember}0 function cannot have a ref-qualifier "
-  "'%select{&&|&}1'">;
+  "%select{static |non-}0member function %select{of type %2 |}1"
+  "cannot have '%3' qualifier">;
+def err_compound_qualified_function_type : Error<
+  "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1"
+  "cannot have '%3' qualifier">;
 
 def err_ref_qualifier_overload : Error<
   "cannot overload a member function %select{without a ref-qualifier|with "

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Fri Feb 10 05:05:11 2012
@@ -498,9 +498,10 @@
   ParsedType DefaultArg;
   if (Tok.is(tok::equal)) {
     EqualLoc = ConsumeToken();
-    DefaultArg = ParseTypeName().get();
+    DefaultArg = ParseTypeName(/*Range=*/0,
+                               Declarator::TemplateTypeArgContext).get();
   }
-  
+
   return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis, 
                                     EllipsisLoc, KeyLoc, ParamName, NameLoc,
                                     Depth, Position, EqualLoc, DefaultArg);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Feb 10 05:05:11 2012
@@ -4341,24 +4341,6 @@
     return false;
   }
 
-  // Function pointers and references cannot have qualified function type, only
-  // function pointer-to-members can do that.
-  QualType Pointee;
-  unsigned PtrOrRef = 0;
-  if (const PointerType *Ptr = T->getAs<PointerType>())
-    Pointee = Ptr->getPointeeType();
-  else if (const ReferenceType *Ref = T->getAs<ReferenceType>()) {
-    Pointee = Ref->getPointeeType();
-    PtrOrRef = 1;
-  }
-  if (!Pointee.isNull() && Pointee->isFunctionProtoType() &&
-      Pointee->getAs<FunctionProtoType>()->getTypeQuals() != 0) {
-    Diag(NewVD->getLocation(), diag::err_invalid_qualified_function_pointer)
-        << PtrOrRef;
-    NewVD->setInvalidDecl();
-    return false;
-  }
-
   if (!Previous.empty()) {
     MergeVarDecl(NewVD, Previous);
     return true;

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Feb 10 05:05:11 2012
@@ -1789,8 +1789,8 @@
   if (D.getAttributes())
     distributeTypeAttrsFromDeclarator(state, T);
 
-  // C++0x [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
-  // In C++0x, a function declarator using 'auto' must have a trailing return
+  // C++11 [dcl.spec.auto]p5: reject 'auto' if it is not in an allowed context.
+  // In C++11, a function declarator using 'auto' must have a trailing return
   // type (this is checked later) and we can skip this. In other languages
   // using auto, we need to check regardless.
   if (D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto &&
@@ -1852,7 +1852,7 @@
     if (D.isFunctionDeclarator())
       Error = 10;
 
-    // C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator
+    // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator
     // contains a trailing return type. That is only legal at the outermost
     // level. Check all declarator chunks (outermost first) anyway, to give
     // better diagnostics.
@@ -1893,7 +1893,7 @@
     case Declarator::ForContext:
     case Declarator::BlockLiteralContext:
     case Declarator::LambdaExprContext:
-      // C++0x [dcl.type]p3:
+      // C++11 [dcl.type]p3:
       //   A type-specifier-seq shall not define a class or enumeration unless
       //   it appears in the type-id of an alias-declaration (7.1.3) that is not
       //   the declaration of a template-declaration.
@@ -1937,6 +1937,66 @@
   return T;
 }
 
+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>());
+}
+
 static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
                                                 QualType declSpecType,
                                                 TypeSourceInfo *TInfo) {
@@ -1968,6 +2028,11 @@
     D.getContext() == Declarator::AliasDeclContext ||
     D.getContext() == Declarator::AliasTemplateContext;
 
+  // Does T refer to a function type with a cv-qualifier or a ref-qualifier?
+  bool IsQualifiedFunction = T->isFunctionProtoType() &&
+      (T->castAs<FunctionProtoType>()->getTypeQuals() != 0 ||
+       T->castAs<FunctionProtoType>()->getRefQualifier() != RQ_None);
+
   // Walk the DeclTypeInfo, building the recursive type as we go.
   // DeclTypeInfos are ordered from the identifier out, which is
   // opposite of what we want :).
@@ -1975,6 +2040,10 @@
     unsigned chunkIndex = e - i - 1;
     state.setCurrentChunkIndex(chunkIndex);
     DeclaratorChunk &DeclType = D.getTypeObject(chunkIndex);
+    if (IsQualifiedFunction) {
+      checkQualifiedFunction(S, T, DeclType);
+      IsQualifiedFunction = DeclType.Kind == DeclaratorChunk::Paren;
+    }
     switch (DeclType.Kind) {
     case DeclaratorChunk::Paren:
       T = S.BuildParenType(T);
@@ -2056,6 +2125,7 @@
       // does not have a K&R-style identifier list), then the arguments are part
       // of the type, otherwise the argument list is ().
       const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
+      IsQualifiedFunction = FTI.TypeQuals || FTI.hasRefQualifier();
 
       // Check for auto functions and trailing return type and adjust the
       // return type accordingly.
@@ -2407,113 +2477,57 @@
                                   FnTy->getNumArgs(), EPI);
     }
 
-    // C++0x [dcl.fct]p6:
-    //   A ref-qualifier shall only be part of the function type for a
-    //   non-static member function, the function type to which a pointer to
-    //   member refers, or the top-level function type of a function typedef 
-    //   declaration.
-    if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) &&
-        !(D.getContext() == Declarator::TemplateTypeArgContext &&
-          !D.isFunctionDeclarator()) && !IsTypedefName &&
-        (FreeFunction ||
-         D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
-      if (D.getContext() == Declarator::TemplateTypeArgContext) {
-        // Accept qualified function types as template type arguments as a GNU
-        // extension. This is also the subject of C++ core issue 547.
-        std::string Quals;
-        if (FnTy->getTypeQuals() != 0)
-          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;
-        }
-        
-        S.Diag(D.getIdentifierLoc(), 
-             diag::ext_qualified_function_type_template_arg)
-          << Quals;
-      } else {
-        if (FnTy->getTypeQuals() != 0) {
-          if (D.isFunctionDeclarator()) {
-            SourceRange Range = D.getIdentifierLoc();
-            for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
-              const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1);
-              if (Chunk.Kind == DeclaratorChunk::Function &&
-                  Chunk.Fun.TypeQuals != 0) {
-                switch (Chunk.Fun.TypeQuals) {
-                case Qualifiers::Const:
-                  Range = Chunk.Fun.getConstQualifierLoc();
-                  break;
-                case Qualifiers::Volatile:
-                  Range = Chunk.Fun.getVolatileQualifierLoc();
-                  break;
-                case Qualifiers::Const | Qualifiers::Volatile: {
-                    SourceLocation CLoc = Chunk.Fun.getConstQualifierLoc();
-                    SourceLocation VLoc = Chunk.Fun.getVolatileQualifierLoc();
-                    if (S.getSourceManager()
-                        .isBeforeInTranslationUnit(CLoc, VLoc)) {
-                      Range = SourceRange(CLoc, VLoc);
-                    } else {
-                      Range = SourceRange(VLoc, CLoc);
-                    }
-                  }
-                  break;
-                }
-                break;
-              }
-            }
-            S.Diag(Range.getBegin(), diag::err_invalid_qualified_function_type)
-                << FixItHint::CreateRemoval(Range);
-          } else
-            S.Diag(D.getIdentifierLoc(),
-                 diag::err_invalid_qualified_typedef_function_type_use)
-              << FreeFunction;
-        }
-          
-        if (FnTy->getRefQualifier()) {
-          if (D.isFunctionDeclarator()) {
-            SourceLocation Loc = D.getIdentifierLoc();
-            for (unsigned I = 0, N = D.getNumTypeObjects(); I != N; ++I) {
-              const DeclaratorChunk &Chunk = D.getTypeObject(N-I-1);
-              if (Chunk.Kind == DeclaratorChunk::Function &&
-                  Chunk.Fun.hasRefQualifier()) {
-                Loc = Chunk.Fun.getRefQualifierLoc();
-                break;
-              }
-            }
-
-            S.Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
-              << (FnTy->getRefQualifier() == RQ_LValue)
-              << FixItHint::CreateRemoval(Loc);
-          } else {
-            S.Diag(D.getIdentifierLoc(), 
-                 diag::err_invalid_ref_qualifier_typedef_function_type_use)
-              << FreeFunction
-              << (FnTy->getRefQualifier() == RQ_LValue);
-          }
+    // C++11 [dcl.fct]p6 (w/DR1417):
+    // An attempt to specify a function type with a cv-qualifier-seq or a
+    // ref-qualifier (including by typedef-name) is ill-formed unless it is:
+    //  - the function type for a non-static member function,
+    //  - the function type to which a pointer to member refers,
+    //  - the top-level function type of a function typedef declaration or
+    //    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
+    if (IsQualifiedFunction &&
+        !(!FreeFunction &&
+          D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) &&
+        !IsTypedefName &&
+        D.getContext() != Declarator::TemplateTypeArgContext) {
+      SourceLocation Loc = D.getSourceRange().getBegin();
+      SourceRange RemovalRange;
+      unsigned I;
+      if (D.isFunctionDeclarator(I)) {
+        SmallVector<SourceLocation, 4> RemovalLocs;
+        const DeclaratorChunk &Chunk = D.getTypeObject(I);
+        assert(Chunk.Kind == DeclaratorChunk::Function);
+        if (Chunk.Fun.hasRefQualifier())
+          RemovalLocs.push_back(Chunk.Fun.getRefQualifierLoc());
+        if (Chunk.Fun.TypeQuals & Qualifiers::Const)
+          RemovalLocs.push_back(Chunk.Fun.getConstQualifierLoc());
+        if (Chunk.Fun.TypeQuals & Qualifiers::Volatile)
+          RemovalLocs.push_back(Chunk.Fun.getVolatileQualifierLoc());
+        // FIXME: We do not track the location of the __restrict qualifier.
+        //if (Chunk.Fun.TypeQuals & Qualifiers::Restrict)
+        //  RemovalLocs.push_back(Chunk.Fun.getRestrictQualifierLoc());
+        if (!RemovalLocs.empty()) {
+          std::sort(RemovalLocs.begin(), RemovalLocs.end(),
+                    SourceManager::LocBeforeThanCompare(S.getSourceManager()));
+          RemovalRange = SourceRange(RemovalLocs.front(), RemovalLocs.back());
+          Loc = RemovalLocs.front();
         }
-          
-        // Strip the cv-qualifiers and ref-qualifiers from the type.
-        FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
-        EPI.TypeQuals = 0;
-        EPI.RefQualifier = RQ_None;
-          
-        T = Context.getFunctionType(FnTy->getResultType(), 
-                                    FnTy->arg_type_begin(),
-                                    FnTy->getNumArgs(), EPI);
       }
+
+      S.Diag(Loc, diag::err_invalid_qualified_function_type)
+        << FreeFunction << D.isFunctionDeclarator() << T
+        << getFunctionQualifiersAsString(FnTy)
+        << FixItHint::CreateRemoval(RemovalRange);
+
+      // Strip the cv-qualifiers and ref-qualifiers from the type.
+      FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
+      EPI.TypeQuals = 0;
+      EPI.RefQualifier = RQ_None;
+
+      T = Context.getFunctionType(FnTy->getResultType(), 
+                                  FnTy->arg_type_begin(),
+                                  FnTy->getNumArgs(), EPI);
     }
   }
 

Modified: cfe/trunk/test/CXX/class/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class/class.friend/p1.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class/class.friend/p1.cpp Fri Feb 10 05:05:11 2012
@@ -58,7 +58,7 @@
   friend A operator|(const A& r); // expected-error {{overloaded 'operator|' must be a binary operator (has 1 parameter)}}
 
   friend operator bool() const; // expected-error {{must use a qualified name when declaring a conversion operator as a friend}} \
-       // expected-error{{type qualifier is not allowed on this function}}
+       // expected-error{{non-member function cannot have 'const' qualifier}}
 
   typedef void ftypedef();
   friend ftypedef typedeffed_function; // okay (because it's not declared as a member)

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp Fri Feb 10 05:05:11 2012
@@ -60,7 +60,7 @@
 template <const auto (*a)[3] = &ints> class D { }; // expected-error{{'auto' not allowed in template parameter}}
 enum E : auto {}; // expected-error{{'auto' not allowed here}}
 struct F : auto {}; // expected-error{{expected class name}}
-template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed here}}
+template<typename T = auto> struct G { }; // expected-error{{'auto' not allowed in template argument}}
 
 using A = auto; // expected-error{{'auto' not allowed in type alias}}
 

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p2-0x.cpp Fri Feb 10 05:05:11 2012
@@ -15,8 +15,7 @@
   using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
   using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
   using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
-  // FIXME: this is illegal; we incorrectly accept it for typedefs too.
-  using F = void(*)(int n) &&; // expected-err
+  using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
   using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
 
   using H = void(int n); // ok

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=150244&r1=150243&r2=150244&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 Fri Feb 10 05:05:11 2012
@@ -1,20 +1,45 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
 
-void f0() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
-void f1() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+void f0() &; // expected-error {{non-member function cannot have '&' qualifier}}
+void f1() &&; // expected-error {{non-member function cannot have '&&' qualifier}}
+void f2() const volatile &&; // expected-error {{non-member function cannot have 'const volatile &&' qualifier}}
 
 struct X {
-  void f0() &; 
+  void f0() &;
   void f1() &&;
-  static void f2() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
-  static void f3() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+  static void f2() &; // expected-error{{static member function cannot have '&' qualifier}}
+  static void f3() &&; // expected-error{{static member function cannot have '&&' qualifier}}
 };
 
 typedef void func_type_lvalue() &;
 typedef void func_type_rvalue() &&;
 
-func_type_lvalue f2; // expected-error{{nonmember function cannot have a ref-qualifier '&'}}
-func_type_rvalue f3; // expected-error{{nonmember function cannot have a ref-qualifier '&&'}}
+typedef func_type_lvalue *func_type_lvalue_ptr; // expected-error{{pointer to function type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
+typedef func_type_rvalue *func_type_rvalue_ptr; // expected-error{{pointer to function type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
+
+typedef func_type_lvalue &func_type_lvalue_ref; // expected-error{{reference to function type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
+typedef func_type_rvalue &func_type_rvalue_ref; // expected-error{{reference to function type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
+
+template<typename T = func_type_lvalue> struct wrap {
+  typedef T val;
+  typedef T *ptr;
+  typedef T &ref;
+};
+
+using func_type_lvalue = wrap<>::val;
+using func_type_lvalue = wrap<func_type_lvalue>::val;
+using func_type_rvalue = wrap<func_type_rvalue>::val;
+
+using func_type_lvalue_ptr = wrap<>::ptr;
+using func_type_lvalue_ptr = wrap<func_type_lvalue>::ptr;
+using func_type_rvalue_ptr = wrap<func_type_rvalue>::ptr;
+
+using func_type_lvalue_ref = wrap<>::ref;
+using func_type_lvalue_ref = wrap<func_type_lvalue>::ref;
+using func_type_rvalue_ref = wrap<func_type_rvalue>::ref;
+
+func_type_lvalue f2; // expected-error{{non-member function of type 'func_type_lvalue' (aka 'void () &') cannot have '&' qualifier}}
+func_type_rvalue f3; // expected-error{{non-member function of type 'func_type_rvalue' (aka 'void () &&') cannot have '&&' qualifier}}
 
 struct Y {
   func_type_lvalue f0;
@@ -25,4 +50,4 @@
 void (X::*mpf2)() && = &X::f1;
 
 
-void (f() &&); // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+void (f() &&); // expected-error{{non-member function cannot have '&&' qualifier}}

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=150244&r1=150243&r2=150244&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 Fri Feb 10 05:05:11 2012
@@ -1,14 +1,20 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-void f() const; // expected-error{{type qualifier is not allowed on this function}}
+typedef void F() const;
+
+void f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
+F g; // expected-error {{non-member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
 
 struct X {
   void f() const;
-  friend void g() const; // expected-error{{type qualifier is not allowed on this function}}
-  static void h() const; // expected-error{{type qualifier is not allowed on this function}}
+  friend void g() const; // expected-error {{non-member function cannot have 'const' qualifier}}
+  static void h() const; // expected-error {{static member function cannot have 'const' qualifier}}
+  F i; // ok
+  friend F j; // expected-error {{non-member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
+  static F k; // expected-error {{static member function of type 'F' (aka 'void () const') cannot have 'const' qualifier}}
 };
 
 struct Y {
   friend void X::f() const;
-  friend void ::f() const; // expected-error{{type qualifier is not allowed on this function}}
+  friend void ::f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
 };

Modified: cfe/trunk/test/FixIt/fixit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/fixit.cpp (original)
+++ cfe/trunk/test/FixIt/fixit.cpp Fri Feb 10 05:05:11 2012
@@ -162,9 +162,9 @@
   aPtr = br; // expected-error {{assigning to 'AD *' from incompatible type 'BD'; take the address with &}}
 }
 
-void foo1() const {} // expected-error {{type qualifier is not allowed on this function}}
-void foo2() volatile {} // expected-error {{type qualifier is not allowed on this function}}
-void foo3() const volatile {} // expected-error {{type qualifier is not allowed on this function}}
+void foo1() const {} // expected-error {{non-member function cannot have 'const' qualifier}}
+void foo2() volatile {} // expected-error {{non-member function cannot have 'volatile' qualifier}}
+void foo3() const volatile {} // expected-error {{non-member function cannot have 'const volatile' qualifier}}
 
 struct S { void f(int, char); };
 int itsAComma,

Modified: cfe/trunk/test/SemaCXX/alias-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/alias-template.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/alias-template.cpp (original)
+++ cfe/trunk/test/SemaCXX/alias-template.cpp Fri Feb 10 05:05:11 2012
@@ -12,8 +12,7 @@
   template<typename U> using C = virtual void(int n); // expected-error {{type name does not allow function specifier}}
   template<typename U> using D = explicit void(int n); // expected-error {{type name does not allow function specifier}}
   template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}}
-  // FIXME: this is illegal; we incorrectly accept it for typedefs too.
-  template<typename U> using F = void(*)(int n) &&; // expected-err
+  template<typename U> using F = void(*)(int n) &&; // expected-error {{pointer to function type cannot have '&&' qualifier}}
   template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}}
 
   template<typename U> using H = void(int n); // ok

Modified: cfe/trunk/test/SemaCXX/destructor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/destructor.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/destructor.cpp (original)
+++ cfe/trunk/test/SemaCXX/destructor.cpp Fri Feb 10 05:05:11 2012
@@ -16,7 +16,7 @@
 
 struct D {
   static void ~D(int, ...) const { } //                          \
-    // expected-error{{type qualifier is not allowed on this function}} \
+    // expected-error{{static member function cannot have 'const' qualifier}} \
     // expected-error{{destructor cannot be declared 'static'}}  \
     // expected-error{{destructor cannot have any parameters}}   \
     // expected-error{{destructor cannot be variadic}} \

Modified: cfe/trunk/test/SemaCXX/function-type-qual.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/function-type-qual.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/function-type-qual.cpp (original)
+++ cfe/trunk/test/SemaCXX/function-type-qual.cpp Fri Feb 10 05:05:11 2012
@@ -1,17 +1,17 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-void f() const; // expected-error {{type qualifier is not allowed on this function}}
-void (*pf)() const; // expected-error {{type qualifier is not allowed on this function pointer}}
-void (&rf)() const = f; // expected-error {{type qualifier is not allowed on this function reference}}
+void f() const; // expected-error {{non-member function cannot have 'const' qualifier}}
+void (*pf)() const; // expected-error {{pointer to function type cannot have 'const' qualifier}}
+extern void (&rf)() const; // expected-error {{reference to function type cannot have 'const' qualifier}}
 
-typedef void cfn() const; 
-cfn f2; // expected-error {{a qualified function type cannot be used to declare a nonmember function}}
+typedef void cfn() const;
+cfn f2; // expected-error {{non-member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}}
 
 class C {
   void f() const;
   cfn f2;
-  static void f3() const; // expected-error {{type qualifier is not allowed on this function}}
-  static cfn f4; // expected-error {{a qualified function type cannot be used to declare a static member function}}
+  static void f3() const; // expected-error {{static member function cannot have 'const' qualifier}}
+  static cfn f4; // expected-error {{static member function of type 'cfn' (aka 'void () const') cannot have 'const' qualifier}}
 
   void m1() {
     x = 0;

Modified: cfe/trunk/test/SemaCXX/issue547.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/issue547.cpp?rev=150244&r1=150243&r2=150244&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/issue547.cpp (original)
+++ cfe/trunk/test/SemaCXX/issue547.cpp Fri Feb 10 05:05:11 2012
@@ -11,17 +11,17 @@
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args...) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+struct classify_function<R(Args...) const> {
   static const unsigned value = 2;
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args...) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args...) volatile> {
   static const unsigned value = 3;
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args...) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args...) const volatile> {
   static const unsigned value = 4;
 };
 
@@ -31,27 +31,27 @@
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args......) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) const> {
   static const unsigned value = 6;
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args......) volatile> { // expected-warning{{template argument of 'volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) volatile> {
   static const unsigned value = 7;
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args......) const volatile> { // expected-warning{{template argument of 'const volatile' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) const volatile> {
   static const unsigned value = 8;
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args......) &&> { // expected-warning{{template argument of '&&' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) &&> {
   static const unsigned value = 9;
 };
 
 template<typename R, typename ...Args>
-struct classify_function<R(Args......) const &> { // expected-warning{{template argument of 'const &' qualified function type is a GNU extension}}
+struct classify_function<R(Args......) const &> {
   static const unsigned value = 10;
 };
 





More information about the cfe-commits mailing list