This rule is part of MISRA C++:2023.
Usage of this content is governed by Sonar’s terms and conditions. Redistribution is
prohibited.
Rule 0.2.3 - Types with limited visibility should be used [1] at least once
Category: Advisory
Analysis: Decidable,Single Translation Unit
Amplification
A type has limited visibility if it is declared in block scope or in unnamed namespace scope.
For the purposes of this rule:
- Type aliases, primary class templates, and alias templates are considered types.
- The closure type associated with a lambda is always used [1].
- A type is used [1] if it is referenced within the translation unit outside of its definition.
- An enumeration type is used [1] if any of its enumerators are used [1].
- An anonymous union is used [1] if any of its members are used [1].
- The definition of a type includes the definition of its members and hidden friends.
- The definition of a class template includes its partial and explicit specializations.
Rationale
If a type is declared but not used [1], then it is unclear to a reviewer if the type is redundant or it has been left unused by
mistake.
Exception
This rule does not apply to:
- Types that have at least one declaration [2] with the
[[maybe_unused]] attribute.
- Template parameters.
- Partial or explicit specializations of class templates.
Example
int16_t f1()
{
using T1 = int16_t; // Non-compliant
using T2 [[maybe_unused]] = int32_t; // Compliant by exception #1
return 67;
}
namespace
{
struct A1 { A1 f(); }; // Compliant
struct A2 { A2 f(); }; // Non-compliant
struct A2; // Not a use of A2
A2 A2::f() { return *this; } // Not a use of A2
template< typename T > // Compliant by exception #2
void foo()
{
A1 a; // Use of A1
a.f(); // - even if foo is not instantiated
}
}
template< bool cond >
inline auto foo()
{
struct res { int32_t i; }; // Compliant
if constexpr ( cond )
{
return 42;
}
else
{
return res { 42 }; // res is utilized, even if cond is true
}
}
template< typename >
int32_t bar()
{
return 42;
}
int32_t f2()
{
return bar< struct P >(); // Compliant - P is used
}
namespace
{
template< typename > struct C1 {}; // Non-compliant
// - C1 only utilized in its definition
template<> struct C1< int32_t > // Compliant by exception #3
{
void mbr()
{
C1< char > cc;
}
};
}
namespace
{
template< typename > struct C2 {}; // Compliant - C2< float > used
template<> struct C2< int32_t >; // Compliant by exception #3
C2< float > cf; // Use of C2
}
namespace
{
static union // Non-compliant
{
int32_t i1;
int32_t j1;
};
static union // Compliant
{
int32_t i2;
int32_t j2;
};
}
void f3()
{
++i2; // Uses the anonymous union holding i2
}
namespace
{
void f4()
{
[]( auto ){}; // Compliant - closure type is always used
}
}
Glossary
[1] Use / used / using
An object is used if:
- It is the subject of a cast; or
- It is explicitly initialized at declaration time; or
- It is an operand in an expression; or
- It is referenced.
A function is used as defined in M23_331: MISRA C++ 2023 Rule 0.2.4.
A type is used as defined in M23_005: MISRA C++ 2023 Rule 0.2.3.
[2] Declaration
A declaration introduces the name of an entity into a translation unit (see [basic.def]/1).
An entity may be declared several times. The first declaration of an entity in a translation unit is
called an introduction [3]. All subsequent declarations are called redeclarations [4].
A definition [5] is a declaration, as described in [basic.def]/2.
[3] Introduction
See declaration [2].
[4] Redeclaration
See declaration [2].
[5] Definition
See declaration [2].
Copyright The MISRA Consortium Limited © 2023