From 929316e38ff2d8f6aedcab9c2636652050ab6460 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 14 May 2015 19:10:42 +0000 Subject: [PATCH] DR295: cv-qualifiers on function types are ignored in C++. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@237383 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 7 +- lib/Sema/SemaType.cpp | 85 ++++++++++++---------- test/CXX/drs/dr2xx.cpp | 15 ++-- www/cxx_dr_status.html | 2 +- 4 files changed, 64 insertions(+), 45 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 66f5687275..0df7f627bc 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; -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; +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; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 5a6cc2eabe..8729f481d6 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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 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 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 diff --git a/test/CXX/drs/dr2xx.cpp b/test/CXX/drs/dr2xx.cpp index bb1f13ac64..25c853590a 100644 --- a/test/CXX/drs/dr2xx.cpp +++ b/test/CXX/drs/dr2xx.cpp @@ -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 struct X { const T &f; }; - X x = {g}; // FIXME: expected-error {{drops qualifiers}} + X 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 diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index 590867ef12..a43e804a5e 100644 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -1811,7 +1811,7 @@ of class templates 295 CD1 cv-qualifiers on function types - No + SVN 296 -- 2.40.0