Fixed #6230 (SymbolDatabase: Wrong function() is set for token)
This commit is contained in:
parent
7c4a137e14
commit
c5e15950df
|
@ -2935,61 +2935,175 @@ const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *ty
|
|||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/** @todo This function only counts the number of arguments in the function call.
|
||||
It does not take into account function constantness.
|
||||
It does not take into account argument types. This can be difficult because of promotion and conversion operators and casts and because the argument can also be a function call.
|
||||
*/
|
||||
const Function* Scope::findFunction(const Token *tok) const
|
||||
void Scope::findFunctionInBase(const Token * tok, size_t args, std::vector<const Function *> & matches) const
|
||||
{
|
||||
std::list<Function>::const_iterator it;
|
||||
|
||||
// this is a function call so try to find it based on name and arguments
|
||||
for (it = functionList.begin(); it != functionList.end(); ++it) {
|
||||
if (it->tokenDef->str() == tok->str()) {
|
||||
const Function *func = &*it;
|
||||
const Token *end = tok->linkAt(1);
|
||||
if (end) {
|
||||
// check the arguments
|
||||
unsigned int args = 0;
|
||||
const Token *arg = tok->tokAt(2);
|
||||
while (arg && arg != end) {
|
||||
/** @todo check argument type for match */
|
||||
|
||||
// mismatch parameter: passing parameter by address to function, argument is reference
|
||||
if (arg->str() == "&") {
|
||||
// check that function argument type is not mismatching
|
||||
const Variable *funcarg = func->getArgumentVar(args);
|
||||
if (funcarg && funcarg->isReference()) {
|
||||
args = ~0U;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
args++;
|
||||
arg = arg->nextArgument();
|
||||
}
|
||||
|
||||
// check for argument count match or default arguments
|
||||
if (args == func->argCount() ||
|
||||
(args < func->argCount() && args >= func->minArgCount()))
|
||||
return func;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check in base classes
|
||||
if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
|
||||
for (std::size_t i = 0; i < definedType->derivedFrom.size(); ++i) {
|
||||
const Type *base = definedType->derivedFrom[i].type;
|
||||
if (base && base->classScope) {
|
||||
if (base->classScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already
|
||||
continue;
|
||||
const Function * func = base->classScope->findFunction(tok);
|
||||
if (func)
|
||||
return func;
|
||||
|
||||
for (std::list<Function>::const_iterator it = base->classScope->functionList.begin(); it != base->classScope->functionList.end(); ++it) {
|
||||
if (it->tokenDef->str() == tok->str()) {
|
||||
const Function *func = &*it;
|
||||
if (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount())) {
|
||||
matches.push_back(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base->classScope->findFunctionInBase(tok, args, matches);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/** @todo This function only counts the number of arguments in the function call.
|
||||
It does not take into account function constantness.
|
||||
It does not take into account argument types. This can be difficult because of promotion and conversion operators and casts and because the argument can also be a function call.
|
||||
*/
|
||||
const Function* Scope::findFunction(const Token *tok) const
|
||||
{
|
||||
// make sure this is a function call
|
||||
const Token *end = tok->linkAt(1);
|
||||
if (!end)
|
||||
return nullptr;
|
||||
|
||||
std::vector<const Token *> arguments;
|
||||
|
||||
// find all the arguments for this function call
|
||||
const Token *arg = tok->tokAt(2);
|
||||
while (arg && arg != end) {
|
||||
arguments.push_back(arg);
|
||||
arg = arg->nextArgument();
|
||||
}
|
||||
|
||||
std::vector<const Function *> matches;
|
||||
|
||||
// find all the possible functions that could match
|
||||
const std::size_t args = arguments.size();
|
||||
for (std::list<Function>::const_iterator it = functionList.begin(); it != functionList.end(); ++it) {
|
||||
if (it->tokenDef->str() == tok->str()) {
|
||||
const Function *func = &*it;
|
||||
if (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount())) {
|
||||
matches.push_back(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check in base classes
|
||||
findFunctionInBase(tok, args, matches);
|
||||
|
||||
// check each function against the arguments in the function call for a match
|
||||
for (size_t i = 0; i < matches.size(); ++i) {
|
||||
const Function * func = matches[i];
|
||||
size_t same = 0;
|
||||
for (std::size_t j = 0; j < args; ++j) {
|
||||
const Variable *funcarg = func->getArgumentVar(j);
|
||||
// check for a match with a variable
|
||||
if (Token::Match(arguments[j], "%var% ,|)") && arguments[j]->varId()) {
|
||||
const Variable * callarg = check->getVariableFromVarId(arguments[j]->varId());
|
||||
if (callarg->typeStartToken()->str() == funcarg->typeStartToken()->str() &&
|
||||
callarg->typeStartToken()->isUnsigned() == funcarg->typeStartToken()->isUnsigned() &&
|
||||
callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()) {
|
||||
same++;
|
||||
}
|
||||
}
|
||||
|
||||
// check for a match with a numeric literal
|
||||
else if (Token::Match(arguments[j], "%num% ,|)")) {
|
||||
if (MathLib::isInt(arguments[j]->str())) {
|
||||
if (arguments[j]->str().find("ll") != std::string::npos ||
|
||||
arguments[j]->str().find("LL") != std::string::npos) {
|
||||
if (arguments[j]->str().find("u") != std::string::npos ||
|
||||
arguments[j]->str().find("U") != std::string::npos) {
|
||||
if (funcarg->typeStartToken()->str() == "long" &&
|
||||
funcarg->typeStartToken()->isLong() &&
|
||||
funcarg->typeStartToken()->isUnsigned()) {
|
||||
same++;
|
||||
}
|
||||
} else {
|
||||
if (funcarg->typeStartToken()->str() == "long" &&
|
||||
funcarg->typeStartToken()->isLong() &&
|
||||
!funcarg->typeStartToken()->isUnsigned()) {
|
||||
same++;
|
||||
}
|
||||
}
|
||||
} else if (arguments[j]->str().find("l") != std::string::npos ||
|
||||
arguments[j]->str().find("L") != std::string::npos) {
|
||||
if (arguments[j]->str().find("u") != std::string::npos ||
|
||||
arguments[j]->str().find("U") != std::string::npos) {
|
||||
if (funcarg->typeStartToken()->str() == "long" &&
|
||||
!funcarg->typeStartToken()->isLong() &&
|
||||
funcarg->typeStartToken()->isUnsigned()) {
|
||||
same++;
|
||||
}
|
||||
} else {
|
||||
if (funcarg->typeStartToken()->str() == "long" &&
|
||||
!funcarg->typeStartToken()->isLong() &&
|
||||
!funcarg->typeStartToken()->isUnsigned()) {
|
||||
same++;
|
||||
}
|
||||
}
|
||||
} else if (arguments[j]->str().find("u") != std::string::npos ||
|
||||
arguments[j]->str().find("U") != std::string::npos) {
|
||||
if (funcarg->typeStartToken()->str() == "int" &&
|
||||
funcarg->typeStartToken()->isUnsigned()) {
|
||||
same++;
|
||||
} else if (Token::Match(funcarg->typeStartToken(), "char|short")) {
|
||||
same++;
|
||||
}
|
||||
} else {
|
||||
if (funcarg->typeStartToken()->str() == "int" &&
|
||||
!funcarg->typeStartToken()->isUnsigned()) {
|
||||
same++;
|
||||
} else if (Token::Match(funcarg->typeStartToken(), "char|short|int")) {
|
||||
same++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (arguments[j]->str().find("f") != std::string::npos ||
|
||||
arguments[j]->str().find("F") != std::string::npos) {
|
||||
if (funcarg->typeStartToken()->str() == "float") {
|
||||
same++;
|
||||
}
|
||||
} else if (arguments[j]->str().find("l") != std::string::npos ||
|
||||
arguments[j]->str().find("L") != std::string::npos) {
|
||||
if (funcarg->typeStartToken()->str() == "double" &&
|
||||
funcarg->typeStartToken()->isLong()) {
|
||||
same++;
|
||||
}
|
||||
} else {
|
||||
if (funcarg->typeStartToken()->str() == "double" &&
|
||||
!funcarg->typeStartToken()->isLong()) {
|
||||
same++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that function argument type is not mismatching
|
||||
else if (arguments[j]->str() == "&" && funcarg && funcarg->isReference()) {
|
||||
// can't match so remove this function from possible matches
|
||||
matches.erase(matches.begin() + i--);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if all arguments matched
|
||||
if (same == args) {
|
||||
// found a match
|
||||
return func;
|
||||
}
|
||||
}
|
||||
|
||||
// no exact match so just return first function found
|
||||
if (!matches.empty()) {
|
||||
return matches[0];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -796,6 +796,8 @@ private:
|
|||
* @return true if tok points to a variable declaration, false otherwise
|
||||
*/
|
||||
bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const;
|
||||
|
||||
void findFunctionInBase(const Token * tok, size_t args, std::vector<const Function *> & matches) const;
|
||||
};
|
||||
|
||||
class CPPCHECKLIB SymbolDatabase {
|
||||
|
|
|
@ -135,6 +135,7 @@ private:
|
|||
TEST_CASE(uninitVar25); // ticket #4789
|
||||
TEST_CASE(uninitVar26);
|
||||
TEST_CASE(uninitVar27); // ticket #5170 - rtl::math::setNan(&d)
|
||||
TEST_CASE(uninitVar28); // ticket #6258
|
||||
TEST_CASE(uninitVarEnum);
|
||||
TEST_CASE(uninitVarStream);
|
||||
TEST_CASE(uninitVarTypedef);
|
||||
|
@ -2110,6 +2111,21 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void uninitVar28() {
|
||||
check("class Fred {\n"
|
||||
" int i;\n"
|
||||
" float f;\n"
|
||||
"public:\n"
|
||||
" Fred() {\n"
|
||||
" foo(1);\n"
|
||||
" foo(1.0f);\n"
|
||||
" }\n"
|
||||
" void foo(int a) { i = a; }\n"
|
||||
" void foo(float a) { f = a; }\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void uninitVarArray1() {
|
||||
check("class John\n"
|
||||
"{\n"
|
||||
|
|
|
@ -228,6 +228,7 @@ private:
|
|||
TEST_CASE(findFunction2); // mismatch: parameter passed by address => reference argument
|
||||
TEST_CASE(findFunction3);
|
||||
TEST_CASE(findFunction4);
|
||||
TEST_CASE(findFunction5); // #6230
|
||||
|
||||
TEST_CASE(noexceptFunction1);
|
||||
TEST_CASE(noexceptFunction2);
|
||||
|
@ -2248,88 +2249,107 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( 1 ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( 1U ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( 1UL ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( 1ULL ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( 1.0F ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( 1.0 ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( 1.0L ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( i ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( ui ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( ul ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( ull ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( f ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( d ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( ld ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( ri ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( rui ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( rul ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( rull ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( rf ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( rd ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( rld ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( cri ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( crui ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( crul ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( crull ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( crf ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( crd ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo ( crld ) ;");
|
||||
TODO_ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8, false);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8);
|
||||
}
|
||||
|
||||
void findFunction5() {
|
||||
GET_SYMBOL_DB("struct Fred {\n"
|
||||
" void Sync(dsmp_t& type, int& len, int limit = 123);\n"
|
||||
" void Sync(int& syncpos, dsmp_t& type, int& len, int limit = 123);\n"
|
||||
" void FindSyncPoint();\n"
|
||||
"};\n"
|
||||
"void Fred::FindSyncPoint() {\n"
|
||||
" dsmp_t type;\n"
|
||||
" int syncpos, len;\n"
|
||||
" Sync(syncpos, type, len);\n"
|
||||
" Sync(type, len);\n"
|
||||
"}");
|
||||
const Token *f = Token::findsimplematch(tokenizer.tokens(), "Sync ( syncpos");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "Sync ( type");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
|
||||
}
|
||||
|
||||
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
|
||||
|
|
|
@ -68,6 +68,7 @@ private:
|
|||
TEST_CASE(uninitvar2_4494); // #4494
|
||||
TEST_CASE(uninitvar2_malloc); // malloc returns uninitialized data
|
||||
TEST_CASE(uninitvar7); // ticket #5971
|
||||
TEST_CASE(uninitvar8); // ticket #6230
|
||||
|
||||
TEST_CASE(syntax_error); // Ticket #5073
|
||||
|
||||
|
@ -2649,6 +2650,21 @@ private:
|
|||
checkUninitVar2(code, "test.cpp");
|
||||
}
|
||||
|
||||
void uninitvar8() {
|
||||
const char code[] = "struct Fred {\n"
|
||||
" void Sync(dsmp_t& type, int& len, int limit = 123);\n"
|
||||
" void Sync(int& syncpos, dsmp_t& type, int& len, int limit = 123);\n"
|
||||
" void FindSyncPoint();\n"
|
||||
"};\n"
|
||||
"void Fred::FindSyncPoint() {\n"
|
||||
" dsmp_t type;\n"
|
||||
" int syncpos, len;\n"
|
||||
" Sync(syncpos, type, len);\n"
|
||||
"}";
|
||||
checkUninitVar2(code, "test.cpp");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
// Handling of function calls
|
||||
void uninitvar2_func() {
|
||||
// non-pointer variable
|
||||
|
|
Loading…
Reference in New Issue