From 12bf8fd6185ed0a44342c868e75c014d64a7544d Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 28 Feb 2024 14:32:26 +0100 Subject: [PATCH] synqt.cpp: scan for and reject #pragma once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 2022¹, we gave ourselves the rule to allow #pragma once only in non-installed headers (examples, tools, snippets, ...), because the same installed header may reside in different places in the filesystem and #pragma once would treat these as separate headers, causing multiple-definition errors. Recently, the question came up: "What constitutes a public header?" Non-_p.h headers in e.g. src/plugins/ muddy the waters here a bit. Since #pragma once is forbidden in installed headers, I had the idea to use it to indicate non-installed headers. This patch enables use of #pragma once as a static assertion to that effect, should we so choose. ¹ https://lists.qt-project.org/pipermail/development/2022-October/043121.html Pick-to: 6.6 6.5 Fixes: QTBUG-122813 Change-Id: I3b5beef72e154cf5bf1ccd4b6f02df9680609e43 Reviewed-by: Volker Hilsheimer Reviewed-by: Ivan Solovev Reviewed-by: Alexey Edelev (cherry picked from commit 1c8884fc277c5916a420a3c14de68547a391f9fc) Reviewed-by: Qt Cherry-pick Bot --- src/tools/syncqt/main.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/tools/syncqt/main.cpp b/src/tools/syncqt/main.cpp index 876860a1876..be6d442a6ff 100644 --- a/src/tools/syncqt/main.cpp +++ b/src/tools/syncqt/main.cpp @@ -43,9 +43,10 @@ enum HeaderChecks { PrivateHeaderChecks = 2, /* Checks if the public header includes a private header */ IncludeChecks = 4, /* Checks if the real header file but not an alias is included */ WeMeantItChecks = 8, /* Checks if private header files contains 'We meant it' disclaimer */ - CriticalChecks = PrivateHeaderChecks, /* Checks that lead to the fatal error of the sync - process */ - AllChecks = NamespaceChecks | PrivateHeaderChecks | IncludeChecks | WeMeantItChecks, + PragmaOnceChecks = 16, + /* Checks that lead to the fatal error of the sync process: */ + CriticalChecks = PrivateHeaderChecks | PragmaOnceChecks, + AllChecks = NamespaceChecks | CriticalChecks | IncludeChecks | WeMeantItChecks, }; constexpr int LinkerScriptCommentAlignment = 55; @@ -1084,6 +1085,9 @@ public: static const std::regex MacroRegex("^\\s*#.*"); // The regex's bellow check line for known pragmas: + // + // - 'once' is not allowed in installed headers, so error out. + // // - 'qt_sync_skip_header_check' avoid any header checks. // // - 'qt_sync_stop_processing' stops the header proccesing from a moment when pragma is @@ -1111,6 +1115,7 @@ public: // // - 'qt_no_master_include' indicates that syncqt should avoid including this header // files into the module master header file. + static const std::regex OnceRegex(R"(^#\s*pragma\s+once$)"); static const std::regex SkipHeaderCheckRegex("^#\\s*pragma qt_sync_skip_header_check$"); static const std::regex StopProcessingRegex("^#\\s*pragma qt_sync_stop_processing$"); static const std::regex SuspendProcessingRegex("^#\\s*pragma qt_sync_suspend_processing$"); @@ -1298,6 +1303,13 @@ public: } else if (std::regex_match(buffer, match, DeprecatesPragmaRegex)) { m_deprecatedHeaders[match[1].str()] = m_commandLineArgs->moduleName() + '/' + m_currentFilename; + } else if (std::regex_match(buffer, OnceRegex)) { + if (!(skipChecks & PragmaOnceChecks)) { + faults |= PragmaOnceChecks; + error() << "\"#pragma once\" is not allowed in installed header files: " + "https://lists.qt-project.org/pipermail/development/2022-October/043121.html" + << std::endl; + } } else if (std::regex_match(buffer, match, IncludeRegex) && !isSuspended) { if (!(skipChecks & IncludeChecks)) { std::string includedHeader = match[1].str();