]> granicus.if.org Git - clang/commitdiff
DR295: cv-qualifiers on function types are ignored in C++.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 14 May 2015 19:10:42 +0000 (19:10 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 14 May 2015 19:10:42 +0000 (19:10 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@237383 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaType.cpp
test/CXX/drs/dr2xx.cpp
www/cxx_dr_status.html

index 66f56872759f931684808c24d06351387b734b0f..0df7f627bceb88b2b776a29afd01634669f80e08 100644 (file)
@@ -4155,8 +4155,11 @@ def err_typecheck_negative_array_size : Error<"array size is negative">;
 def warn_typecheck_negative_array_new_size : Warning<"array size is negative">,
   // FIXME PR11644: ", will throw std::bad_array_new_length at runtime"
   InGroup<BadArrayNewLength>;
-def warn_typecheck_function_qualifiers : Warning<
-  "qualifier on function type %0 has unspecified behavior">;
+def warn_typecheck_function_qualifiers_ignored : Warning<
+  "'%0' qualifier on function type %1 has no effect">,
+  InGroup<IgnoredQualifiers>;
+def warn_typecheck_function_qualifiers_unspecified : Warning<
+  "'%0' qualifier on function type %1 has unspecified behavior">;
 def warn_typecheck_reference_qualifiers : Warning<
   "'%0' qualifier on reference type %1 has no effect">,
   InGroup<IgnoredQualifiers>;
index 5a6cc2eabe382d45d7d584bc2ba9f12f14071360..8729f481d6d30e18ab726e27eec9991083028adf 100644 (file)
@@ -688,6 +688,33 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state,
   state.setCurrentChunkIndex(declarator.getNumTypeObjects());
 }
 
+void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS,
+                                     unsigned &TypeQuals, QualType TypeSoFar,
+                                     unsigned RemoveTQs, unsigned DiagID) {
+  // If this occurs outside a template instantiation, warn the user about
+  // it; they probably didn't mean to specify a redundant qualifier.
+  typedef std::pair<DeclSpec::TQ, SourceLocation> QualLoc;
+  QualLoc Quals[] = {
+    QualLoc(DeclSpec::TQ_const, DS.getConstSpecLoc()),
+    QualLoc(DeclSpec::TQ_volatile, DS.getVolatileSpecLoc()),
+    QualLoc(DeclSpec::TQ_atomic, DS.getAtomicSpecLoc())
+  };
+
+  for (unsigned I = 0, N = llvm::array_lengthof(Quals); I != N; ++I) {
+    if (!(RemoveTQs & Quals[I].first))
+      continue;
+
+    if (S.ActiveTemplateInstantiations.empty()) {
+      if (TypeQuals & Quals[I].first)
+        S.Diag(Quals[I].second, DiagID)
+          << DeclSpec::getSpecifierName(Quals[I].first) << TypeSoFar
+          << FixItHint::CreateRemoval(Quals[I].second);
+    }
+
+    TypeQuals &= ~Quals[I].first;
+  }
+}
+
 /// \brief Convert the specified declspec to the appropriate type
 /// object.
 /// \param state Specifies the declarator containing the declaration specifier
@@ -1117,24 +1144,22 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
 
   // Apply const/volatile/restrict qualifiers to T.
   if (unsigned TypeQuals = DS.getTypeQualifiers()) {
-
-    // Warn about CV qualifiers on functions: C99 6.7.3p8: "If the specification
-    // of a function type includes any type qualifiers, the behavior is
-    // undefined."
-    if (Result->isFunctionType() && TypeQuals) {
-      if (TypeQuals & DeclSpec::TQ_const)
-        S.Diag(DS.getConstSpecLoc(), diag::warn_typecheck_function_qualifiers)
-          << Result << DS.getSourceRange();
-      else if (TypeQuals & DeclSpec::TQ_volatile)
-        S.Diag(DS.getVolatileSpecLoc(),
-               diag::warn_typecheck_function_qualifiers)
-            << Result << DS.getSourceRange();
-      else {
-        assert((TypeQuals & (DeclSpec::TQ_restrict | DeclSpec::TQ_atomic)) &&
-               "Has CVRA quals but not C, V, R, or A?");
-        // No diagnostic; we'll diagnose 'restrict' or '_Atomic' applied to a
-        // function type later, in BuildQualifiedType.
-      }
+    // Warn about CV qualifiers on function types.
+    // C99 6.7.3p8:
+    //   If the specification of a function type includes any type qualifiers,
+    //   the behavior is undefined.
+    // C++11 [dcl.fct]p7:
+    //   The effect of a cv-qualifier-seq in a function declarator is not the
+    //   same as adding cv-qualification on top of the function type. In the
+    //   latter case, the cv-qualifiers are ignored.
+    if (TypeQuals && Result->isFunctionType()) {
+      diagnoseAndRemoveTypeQualifiers(
+          S, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile,
+          S.getLangOpts().CPlusPlus
+              ? diag::warn_typecheck_function_qualifiers_ignored
+              : diag::warn_typecheck_function_qualifiers_unspecified);
+      // No diagnostic for 'restrict' or '_Atomic' applied to a
+      // function type; we'll diagnose those later, in BuildQualifiedType.
     }
 
     // C++11 [dcl.ref]p1:
@@ -1145,25 +1170,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
     // There don't appear to be any other contexts in which a cv-qualified
     // reference type could be formed, so the 'ill-formed' clause here appears
     // to never happen.
-    if (DS.getTypeSpecType() == DeclSpec::TST_typename &&
-        TypeQuals && Result->isReferenceType()) {
-      // If this occurs outside a template instantiation, warn the user about
-      // it; they probably didn't mean to specify a redundant qualifier.
-      typedef std::pair<DeclSpec::TQ, SourceLocation> QualLoc;
-      QualLoc Quals[] = {
-        QualLoc(DeclSpec::TQ_const, DS.getConstSpecLoc()),
-        QualLoc(DeclSpec::TQ_volatile, DS.getVolatileSpecLoc()),
-        QualLoc(DeclSpec::TQ_atomic, DS.getAtomicSpecLoc())
-      };
-      for (unsigned I = 0, N = llvm::array_lengthof(Quals); I != N; ++I) {
-        if (S.ActiveTemplateInstantiations.empty()) {
-          if (TypeQuals & Quals[I].first)
-            S.Diag(Quals[I].second, diag::warn_typecheck_reference_qualifiers)
-              << DeclSpec::getSpecifierName(Quals[I].first) << Result
-              << FixItHint::CreateRemoval(Quals[I].second);
-        }
-        TypeQuals &= ~Quals[I].first;
-      }
+    if (TypeQuals && Result->isReferenceType()) {
+      diagnoseAndRemoveTypeQualifiers(
+          S, DS, TypeQuals, Result,
+          DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic,
+          diag::warn_typecheck_reference_qualifiers);
     }
 
     // C90 6.5.3 constraints: "The same type qualifier shall not appear more
index bb1f13ac64ee74f8f6a286134c846c8ef7309179..25c853590ae66963e293ac48c270d45d65ab2fa9 100644 (file)
@@ -999,15 +999,20 @@ namespace dr294 { // dr294: no
   }
 }
 
-namespace dr295 { // dr295: no
+namespace dr295 { // dr295: 3.7
   typedef int f();
-  // FIXME: This warning is incorrect.
-  const f g; // expected-warning {{unspecified behavior}}
-  const f &r = g; // expected-warning {{unspecified behavior}}
+  const f g; // expected-warning {{'const' qualifier on function type 'f' (aka 'int ()') has no effect}}
+  f &r = g;
   template<typename T> struct X {
     const T &f;
   };
-  X<f> x = {g}; // FIXME: expected-error {{drops qualifiers}}
+  X<f> x = {g};
+
+  typedef int U();
+  typedef const U U; // expected-warning {{'const' qualifier on function type 'U' (aka 'int ()') has no effect}}
+
+  typedef int (*V)();
+  typedef volatile U *V; // expected-warning {{'volatile' qualifier on function type 'U' (aka 'int ()') has no effect}}
 }
 
 namespace dr296 { // dr296: yes
index 590867ef12b682b8555c7ec4cd43948832d91629..a43e804a5ea0f6edbdde229487d5005214044fd0 100644 (file)
@@ -1811,7 +1811,7 @@ of class templates</td>
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#295">295</a></td>
     <td>CD1</td>
     <td>cv-qualifiers on function types</td>
-    <td class="none" align="center">No</td>
+    <td class="svn" align="center">SVN</td>
   </tr>
   <tr id="296">
     <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#296">296</a></td>