From c358050b4c4b25b7326e0da2168c608d1a84757f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Wed, 5 Jun 2024 22:12:29 +0200 Subject: [PATCH] Fix #12813 (Tokenizer: handle alignas in C11 code) (#6487) --- lib/tokenize.cpp | 50 ++++++++++++++++++++++++------------- test/testsymboldatabase.cpp | 2 +- test/testtokenize.cpp | 11 ++++++++ 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 840b3021c67f..51a465de65d1 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9223,7 +9223,11 @@ void Tokenizer::simplifyCppcheckAttribute() void Tokenizer::simplifyCPPAttribute() { - if (!isCPP() || mSettings.standards.cpp < Standards::CPP11) + // According to cppreference alignas is a c21 feature however the macro is often available when compiling c11 + const bool hasAlignas = ((isCPP() && mSettings.standards.cpp >= Standards::CPP11) || (isC() && mSettings.standards.c >= Standards::C11)); + const bool hasCppAttribute = (isCPP() && mSettings.standards.cpp >= Standards::CPP11); + + if (!hasAlignas && !hasCppAttribute) return; for (Token *tok = list.front(); tok;) { @@ -9232,6 +9236,10 @@ void Tokenizer::simplifyCPPAttribute() continue; } if (isCPPAttribute(tok)) { + if (!hasCppAttribute) { + tok = skipCPPOrAlignAttribute(tok)->next(); + continue; + } if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) { Token * head = skipCPPOrAlignAttribute(tok)->next(); while (isCPPAttribute(head) || isAlignAttribute(head)) @@ -9283,23 +9291,29 @@ void Tokenizer::simplifyCPPAttribute() } } } else { - if (Token::simpleMatch(tok, "alignas (")) { - Token* atok = nullptr; - if (Token::Match(tok->previous(), "%name%")) - atok = tok->previous(); - else { - atok = tok; - while (isCPPAttribute(atok) || isAlignAttribute(atok)) - atok = skipCPPOrAlignAttribute(atok)->next(); - } - if (atok) { - std::string a; - for (const Token* t = tok->tokAt(2); t && t->str() != ")"; t = t->next()) - a += " " + t->str(); - if (a.size() > 1) - atok->addAttributeAlignas(a.substr(1)); - } - // alignment requirements could be checked here + // alignas(expr) + + if (!hasAlignas) { + tok = skipCPPOrAlignAttribute(tok)->next(); + continue; + } + + // alignment requirements could be checked here + + Token* atok = nullptr; + if (Token::Match(tok->previous(), "%name%")) + atok = tok->previous(); + else { + atok = tok; + while (isCPPAttribute(atok) || isAlignAttribute(atok)) + atok = skipCPPOrAlignAttribute(atok)->next(); + } + if (atok) { + std::string a; + for (const Token* t = tok->tokAt(2); t && t->str() != ")"; t = t->next()) + a += " " + t->str(); + if (a.size() > 1) + atok->addAttributeAlignas(a.substr(1)); } } Token::eraseTokens(tok, skipCPPOrAlignAttribute(tok)->next()); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 0b248165d5cc..4fa7716440bc 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -1715,7 +1715,7 @@ class TestSymbolDatabase : public TestFixture { ASSERT(db); ASSERT_EQUALS(2, db->scopeList.front().varlist.size()); const Variable *x1 = Token::findsimplematch(tokenizer.tokens(), "x")->variable(); - ASSERT(x1 && Token::simpleMatch(x1->typeStartToken(), "alignas ( 16 ) int x ;")); + ASSERT(x1 && Token::simpleMatch(x1->typeStartToken(), "int x ;")); } void memberVar1() { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 004058bf4254..6b7360f45a58 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -438,6 +438,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(removeAlignas1); TEST_CASE(removeAlignas2); // Do not remove alignof in the same way + TEST_CASE(removeAlignas3); // remove alignas in C11 code TEST_CASE(dumpAlignas); TEST_CASE(simplifyCoroutines); @@ -7765,6 +7766,16 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } + void removeAlignas3() { + const char code[] = "alignas(16) int x;"; + const char expected[] = "int x ;"; + // According to cppreference alignas() is a C23 macro; but it is often available when compiling C11. + // Misra C has C11 examples with alignas. + // Microsoft provides alignas in C11. + ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, Platform::Type::Native, false, Standards::CPP11)); + ASSERT_EQUALS(expected, tokenizeAndStringify(code, true, Platform::Type::Native, true, Standards::CPP11)); + } + void dumpAlignas() { Settings settings; SimpleTokenizer tokenizer(settings, *this);