[cfe-commits] r124584 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h include/clang/Sema/DeclSpec.h lib/Parse/ParseDecl.cpp lib/Parse/ParseTemplate.cpp lib/Sema/SemaType.cpp test/SemaCXX/issue547.cpp

Douglas Gregor dgregor at apple.com
Mon Jan 31 08:09:46 PST 2011


Author: dgregor
Date: Mon Jan 31 10:09:46 2011
New Revision: 124584

URL: http://llvm.org/viewvc/llvm-project?rev=124584&view=rev
Log:
Implement the suggested resolution to core issue 547, extended to also
allow ref-qualifiers on function types used as template type
arguments. GNU actually allows cv-qualifiers on function types in many
places where it shouldn't, so we currently categorize this as a GNU
extension.

Added:
    cfe/trunk/test/SemaCXX/issue547.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Sema/SemaType.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 31 10:09:46 2011
@@ -2475,6 +2475,10 @@
 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<

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jan 31 10:09:46 2011
@@ -1464,7 +1464,9 @@
   TPResult TryParseFunctionDeclarator();
   TPResult TryParseBracketDeclarator();
 
-  TypeResult ParseTypeName(SourceRange *Range = 0);
+  TypeResult ParseTypeName(SourceRange *Range = 0,
+                           Declarator::TheContext Context
+                                                 = Declarator::TypeNameContext);
   void ParseBlockId();
 
   void ProhibitAttributes(ParsedAttributesWithRange &attrs) {

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Jan 31 10:09:46 2011
@@ -1177,7 +1177,8 @@
     ConditionContext,    // Condition declaration in a C++ if/switch/while/for.
     TemplateParamContext,// Within a template parameter list.
     CXXCatchContext,     // C++ catch exception-declaration
-    BlockLiteralContext  // Block literal declarator.
+    BlockLiteralContext,  // Block literal declarator.
+    TemplateTypeArgContext // Template type argument.
   };
 
 private:
@@ -1302,14 +1303,15 @@
   bool mayOmitIdentifier() const {
     return Context == TypeNameContext || Context == PrototypeContext ||
            Context == TemplateParamContext || Context == CXXCatchContext ||
-           Context == BlockLiteralContext;
+           Context == BlockLiteralContext || Context == TemplateTypeArgContext;
   }
 
   /// mayHaveIdentifier - Return true if the identifier is either optional or
   /// required.  This is true for normal declarators and prototypes, but not
   /// typenames.
   bool mayHaveIdentifier() const {
-    return Context != TypeNameContext && Context != BlockLiteralContext;
+    return Context != TypeNameContext && Context != BlockLiteralContext &&
+           Context != TemplateTypeArgContext;
   }
 
   /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jan 31 10:09:46 2011
@@ -29,13 +29,14 @@
 ///         specifier-qualifier-list abstract-declarator[opt]
 ///
 /// Called type-id in C++.
-TypeResult Parser::ParseTypeName(SourceRange *Range) {
+TypeResult Parser::ParseTypeName(SourceRange *Range,
+                                 Declarator::TheContext Context) {
   // Parse the common declaration-specifiers piece.
   DeclSpec DS;
   ParseSpecifierQualifierList(DS);
 
   // Parse the abstract-declarator, if present.
-  Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+  Declarator DeclaratorInfo(DS, Context);
   ParseDeclarator(DeclaratorInfo);
   if (Range)
     *Range = DeclaratorInfo.getSourceRange();

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Jan 31 10:09:46 2011
@@ -992,7 +992,8 @@
   // Therefore, we initially try to parse a type-id.  
   if (isCXXTypeId(TypeIdAsTemplateArgument)) {
     SourceLocation Loc = Tok.getLocation();
-    TypeResult TypeArg = ParseTypeName();
+    TypeResult TypeArg = ParseTypeName(/*Range=*/0, 
+                                       Declarator::TemplateTypeArgContext);
     if (TypeArg.isInvalid())
       return ParsedTemplateArgument();
     

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=124584&r1=124583&r2=124584&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jan 31 10:09:46 2011
@@ -1512,6 +1512,7 @@
     case Declarator::ForContext:
     case Declarator::ConditionContext:
     case Declarator::TypeNameContext:
+    case Declarator::TemplateTypeArgContext:
       break;
     }
 
@@ -1872,6 +1873,9 @@
     //   for a nonstatic member function, the function type to which a pointer
     //   to member refers, or the top-level function type of a function typedef
     //   declaration.
+    //
+    // Core issue 547 also allows cv-qualifiers on function types that are
+    // top-level template type arguments.
     bool FreeFunction;
     if (!D.getCXXScopeSpec().isSet()) {
       FreeFunction = (D.getContext() != Declarator::MemberContext ||
@@ -1887,48 +1891,81 @@
     //   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()) &&
         D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
         (FreeFunction ||
          D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
-      if (FnTy->getTypeQuals() != 0) {
-        if (D.isFunctionDeclarator())
-          Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
-        else
-          Diag(D.getIdentifierLoc(),
-               diag::err_invalid_qualified_typedef_function_type_use)
-            << FreeFunction;
-      }
+      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;
           
-      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;
+        case RQ_RValue:
+          if (!Quals.empty())
+            Quals += ' ';
+          Quals += "&&";
+          break;
+        }
+        
+        Diag(D.getIdentifierLoc(), 
+             diag::ext_qualified_function_type_template_arg)
+          << Quals;
+      } else {
+        if (FnTy->getTypeQuals() != 0) {
+          if (D.isFunctionDeclarator())
+            Diag(D.getIdentifierLoc(), 
+                 diag::err_invalid_qualified_function_type);
+          else
+            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;
+              }
             }
-          }
 
-          Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
-            << (FnTy->getRefQualifier() == RQ_LValue)
-            << FixItHint::CreateRemoval(Loc);
-        } else {
-          Diag(D.getIdentifierLoc(), 
-               diag::err_invalid_ref_qualifier_typedef_function_type_use)
-            << FreeFunction
-            << (FnTy->getRefQualifier() == RQ_LValue);
+            Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
+              << (FnTy->getRefQualifier() == RQ_LValue)
+              << FixItHint::CreateRemoval(Loc);
+          } else {
+            Diag(D.getIdentifierLoc(), 
+                 diag::err_invalid_ref_qualifier_typedef_function_type_use)
+              << FreeFunction
+              << (FnTy->getRefQualifier() == RQ_LValue);
+          }
         }
-      }
           
-      // Strip the cv-quals and ref-qualifier from the type.
-      FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
-      EPI.TypeQuals = 0;
-      EPI.RefQualifier = RQ_None;
+        // 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);
+        T = Context.getFunctionType(FnTy->getResultType(), 
+                                    FnTy->arg_type_begin(),
+                                    FnTy->getNumArgs(), EPI);
+      }
     }
   }
 
@@ -1997,6 +2034,7 @@
     case Declarator::ConditionContext:
     case Declarator::CXXCatchContext:
     case Declarator::BlockLiteralContext:
+    case Declarator::TemplateTypeArgContext:
       // FIXME: We may want to allow parameter packs in block-literal contexts
       // in the future.
       Diag(D.getEllipsisLoc(), diag::err_ellipsis_in_declarator_not_parameter);

Added: cfe/trunk/test/SemaCXX/issue547.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/issue547.cpp?rev=124584&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/issue547.cpp (added)
+++ cfe/trunk/test/SemaCXX/issue547.cpp Mon Jan 31 10:09:46 2011
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+template<typename T>
+struct classify_function {
+  static const unsigned value = 0;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args...)> {
+  static const unsigned value = 1;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args...) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+  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}}
+  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}}
+  static const unsigned value = 4;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......)> {
+  static const unsigned value = 5;
+};
+
+template<typename R, typename ...Args>
+struct classify_function<R(Args......) const> { // expected-warning{{template argument of 'const' qualified function type is a GNU extension}}
+  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}}
+  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}}
+  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}}
+  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}}
+  static const unsigned value = 10;
+};
+
+typedef void f0(int) const;
+typedef void f1(int, float...) const volatile;
+typedef void f2(int, double, ...) &&;
+typedef void f3(int, double, ...) const &;
+
+int check0[classify_function<f0>::value == 2? 1 : -1];
+int check1[classify_function<f1>::value == 8? 1 : -1];
+int check2[classify_function<f2>::value == 9? 1 : -1];
+int check3[classify_function<f3>::value == 10? 1 : -1];





More information about the cfe-commits mailing list