@@ -111,21 +111,28 @@ CheckClassImpl::CheckClassImpl(const Tokenizer *tokenizer, const Settings &setti
111111 mSymbolDatabase(tokenizer?tokenizer->getSymbolDatabase ():nullptr)
112112{}
113113
114- bool CheckClassImpl::isInitialized (const Usage& usage, FunctionType funcType) const
114+ CheckClassImpl::Initialization CheckClassImpl::checkInitialization (const Usage& usage, FunctionType funcType, bool noConstructor ) const
115115{
116116 const Variable& var = *usage.var ;
117117
118118 if (usage.assign || usage.init || var.isStatic ())
119- return true ;
119+ return Initialization::Initialized ;
120120
121121 if (!var.nameToken () || var.nameToken ()->isAnonymous ())
122- return true ;
122+ return Initialization::None ;
123123
124124 if (var.valueType () && var.valueType ()->pointer == 0 && var.type () && var.type ()->needInitialization == Type::NeedInitialization::False && var.type ()->derivedFrom .empty ())
125- return true ;
125+ return Initialization::Initialized ;
126126
127- if (var.isConst () && funcType == FunctionType::eOperatorEqual) // We can't set const members in assignment operator
128- return true ;
127+ if (var.isConst () && (funcType == FunctionType::eOperatorEqual || // We can't set const members in assignment operator
128+ (funcType == FunctionType::eConstructor && noConstructor))) // a const member of class type is default constructed or makes the class not default constructible
129+ return Initialization::None;
130+
131+ if (funcType == FunctionType::eConstructor && noConstructor && var.nameToken ()->isBitfield () && mSettings .standards .cpp < Standards::CPP20 )
132+ return Initialization::None;
133+
134+ if (var.isArray () && ((var.dimensionKnown (0 ) && var.dimensions ()[0 ].num == 0 ) || Token::simpleMatch (var.nameToken ()->next (), " [ ]" ))) // HACK for unreliable dimensions
135+ return Initialization::None;
129136
130137 // Check if this is a class constructor
131138 if (!var.isPointer () && !var.isPointerArray () && var.isClass () && funcType == FunctionType::eConstructor) {
@@ -141,33 +148,33 @@ bool CheckClassImpl::isInitialized(const Usage& usage, FunctionType funcType) co
141148 if (!ctt->isStandardType () &&
142149 (!ctt->type () || ctt->type ()->needInitialization != Type::NeedInitialization::True) &&
143150 !mSettings .library .podtype (ctt->str ())) // TODO: handle complex type expression
144- return true ;
151+ return Initialization::Initialized ;
145152 }
146153 else
147- return true ;
154+ return Initialization::Initialized ;
148155 }
149156 else
150- return true ;
157+ return Initialization::Initialized ;
151158 }
152159
153160 // Known type that doesn't need initialization or
154161 // known type that has member variables of an unknown type
155162 else if (var.type ()->needInitialization != Type::NeedInitialization::True)
156- return true ;
163+ return Initialization::Initialized ;
157164 }
158165
159166 // Check if type can't be copied
160167 if (!var.isPointer () && !var.isPointerArray () && var.typeScope ()) {
161168 if (funcType == FunctionType::eMoveConstructor) {
162169 if (canNotMove (var.typeScope ()))
163- return true ;
170+ return Initialization::None ;
164171 }
165172 else {
166173 if (canNotCopy (var.typeScope ()))
167- return true ;
174+ return Initialization::None ;
168175 }
169176 }
170- return false ;
177+ return Initialization::Missing ;
171178}
172179
173180void CheckClassImpl::handleUnionMembers (std::vector<Usage>& usageList)
@@ -348,7 +355,7 @@ void CheckClassImpl::constructors()
348355
349356 // Check if any variables are uninitialized
350357 for (const Usage &usage : usageList) {
351- if (isInitialized (usage, func.type ))
358+ if (checkInitialization (usage, func.type ) != Initialization::Missing )
352359 continue ;
353360
354361 // Is there missing member copy in copy/move constructor or assignment operator?
@@ -413,7 +420,7 @@ void CheckClassImpl::constructors()
413420 // Inherited constructors don't initialize members of the derived class
414421 for (const Token *baseCtorTok : inheritedCtors) {
415422 for (const Usage &usage : usageList) {
416- if (isInitialized (usage, FunctionType::eConstructor))
423+ if (checkInitialization (usage, FunctionType::eConstructor) != Initialization::Missing )
417424 continue ;
418425 const Variable& var = *usage.var ;
419426 if (var.typeScope () && var.typeScope ()->numConstructors > 0 )
@@ -443,7 +450,7 @@ void CheckClassImpl::constructors()
443450 } else if (!var.isStatic () && (var.isReference () || (var.isConst () && !var.isClass ()))) {
444451 // the default constructor is deleted, so all members are initialized by every instance
445452 isDefaultConstructible = false ;
446- } else if (cpp14OrLater && !hasAnySelfInit && isInitialized (usage, FunctionType::eConstructor)) {
453+ } else if (cpp14OrLater && !hasAnySelfInit && checkInitialization (usage, FunctionType::eConstructor) == Initialization::Initialized ) {
447454 hasAnySelfInit = true ;
448455 }
449456 }
@@ -454,17 +461,13 @@ void CheckClassImpl::constructors()
454461
455462 // Check if any variables are uninitialized
456463 for (const Usage& usage : usageList) {
457- if (isInitialized (usage, FunctionType::eConstructor) )
464+ if (checkInitialization (usage, FunctionType::eConstructor, /* noConstructor */ true ) != Initialization::Missing )
458465 continue ;
459466
460467 const Variable& var = *usage.var ;
461468 if (var.typeScope () && var.typeScope ()->numConstructors > 0 )
462469 continue ;
463470
464- // a const member of class type is default constructed or makes the class not default constructible
465- if (var.isConst ())
466- continue ;
467-
468471 if (diagVars.count (&var) == 0 )
469472 uninitVarError (var.nameToken (), false , FunctionType::eConstructor, var.scope ()->className , var.name (), false , false , true );
470473 }
0 commit comments