diff options
Diffstat (limited to 'clang')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 85 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr2xx.cpp | 15 | ||||
-rw-r--r-- | clang/www/cxx_dr_status.html | 2 |
4 files changed, 64 insertions, 45 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 66f56872759..0df7f627bce 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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<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>; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 5a6cc2eabe3..8729f481d6d 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/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<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 diff --git a/clang/test/CXX/drs/dr2xx.cpp b/clang/test/CXX/drs/dr2xx.cpp index bb1f13ac64e..25c853590ae 100644 --- a/clang/test/CXX/drs/dr2xx.cpp +++ b/clang/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<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 diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 590867ef12b..a43e804a5ea 100644 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -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> |