Skip to content

Commit

Permalink
DR295: cv-qualifiers on function types are ignored in C++.
Browse files Browse the repository at this point in the history
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@237383 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
zygoloid committed May 14, 2015
1 parent 569e628 commit 929316e
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 45 deletions.
7 changes: 5 additions & 2 deletions include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
85 changes: 48 additions & 37 deletions lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down
15 changes: 10 additions & 5 deletions test/CXX/drs/dr2xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -1811,7 +1811,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<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>
Expand Down

0 comments on commit 929316e

Please sign in to comment.