Index: plugins/clang/clangsupport.cpp =================================================================== --- plugins/clang/clangsupport.cpp +++ plugins/clang/clangsupport.cpp @@ -180,12 +180,13 @@ clangDebug() << "Detected Clang version:" << ClangHelpers::clangVersion(); { - const auto builtinDir = ClangHelpers::clangBuiltinIncludePath(); const auto headerToCheck = QLatin1String("cpuid.h"); - if (!QFile::exists(builtinDir + QLatin1Char('/') + headerToCheck)) { + const auto builtinDir = ClangHelpers::clangBuiltinIncludePath(headerToCheck); + if (builtinDir.isEmpty()) { setErrorDescription(i18n("The clang builtin include path \"%1\" is invalid (missing %2 header).\n" "Try setting the KDEV_CLANG_BUILTIN_DIR environment variable manually to fix this.\n" - "See also: https://bugs.kde.org/show_bug.cgi?id=393779", builtinDir, headerToCheck)); + "See also: https://bugs.kde.org/show_bug.cgi?id=393779", + ClangHelpers::clangBuiltinIncludePath(), headerToCheck)); return; } } Index: plugins/clang/duchain/clanghelpers.h =================================================================== --- plugins/clang/duchain/clanghelpers.h +++ plugins/clang/duchain/clanghelpers.h @@ -104,10 +104,15 @@ /** * @return The path containing Clang built includes (e.g. stddef.h, stdarg.h, cpuid.h) + * The returned path is the env. var KDEV_CLANG_BUILTIN_DIR when set otherwise the path + * to the headers used when kdev-clang was built, possibly updated for minor upgrades to + * the library (e.g. 7.0.0 -> 7.0.1). + * Returns an empty string if none of the checked locations contain the file @a entryToCheck + * (the default entry '.' is present in any directory). * * Also see: https://clang.llvm.org/docs/FAQ.html */ -KDEVCLANGPRIVATE_EXPORT QString clangBuiltinIncludePath(); +KDEVCLANGPRIVATE_EXPORT QString clangBuiltinIncludePath(const QString entryToCheck=QStringLiteral(".")); } Index: plugins/clang/duchain/clanghelpers.cpp =================================================================== --- plugins/clang/duchain/clanghelpers.cpp +++ plugins/clang/duchain/clanghelpers.cpp @@ -369,11 +369,11 @@ return clangVersion; } -QString ClangHelpers::clangBuiltinIncludePath() +QString ClangHelpers::clangBuiltinIncludePath(const QString entryToCheck) { - static const auto dir = []() -> QString { + static const auto dir = [entryToCheck]() -> QString { auto dir = QString::fromUtf8(qgetenv("KDEV_CLANG_BUILTIN_DIR")); - if (!dir.isEmpty()) { + if (!dir.isEmpty() && QFile::exists(dir + QLatin1Char('/') + entryToCheck)) { clangDebug() << "Using dir from $KDEV_CLANG_BUILTIN_DIR:" << dir; return dir; } @@ -383,13 +383,31 @@ dir = QDir::cleanPath(QStringLiteral("%1/../lib/clang/%2/include") .arg(QCoreApplication::applicationDirPath(), clangVersion())); clangDebug() << "Trying" << dir; - if (QFileInfo(dir).isDir()) { + if (QFileInfo(dir).isDir() + && QFile::exists(dir + QLatin1Char('/') + entryToCheck)) { return dir; } +#elif defined(Q_OS_UNIX) + // a clang minor version upgrade since we were last built can + // cause problems if the "clang/$fullversion/include" path component + // changed. Try to generate the correct builtin_dir for the current + // major.minor.patchlevel version: pop the last 2 components then + // chdir through with the updated version directory. + auto hardcodedDir = QDir(QStringLiteral(KDEV_CLANG_BUILTIN_DIR)); + if (hardcodedDir.cd(QStringLiteral("../../%1/include").arg(clangVersion())) + && QFile::exists(hardcodedDir.path() + QLatin1Char('/') + entryToCheck)) { + clangDebug() << "Using builtin dir:" << hardcodedDir.path(); + return hardcodedDir.path(); + } #endif - clangDebug() << "Using builtin dir:" << KDEV_CLANG_BUILTIN_DIR; - return QString::fromUtf8(KDEV_CLANG_BUILTIN_DIR); + dir = QString::fromUtf8(KDEV_CLANG_BUILTIN_DIR); + if (QFile::exists(dir + QLatin1Char('/') + entryToCheck)) { + clangDebug() << "Using builtin dir:" << KDEV_CLANG_BUILTIN_DIR; + return dir; + } + // return empty string to signal failure + return QString(); }(); return dir; } Index: plugins/clang/duchain/parsesession.cpp =================================================================== --- plugins/clang/duchain/parsesession.cpp +++ plugins/clang/duchain/parsesession.cpp @@ -273,8 +273,12 @@ addFrameworkDirectories(&clangArguments, &smartArgs, frameworkDirectories.project, "-F"); // libclang cannot find it's builtin dir automatically, we have to specify it manually - smartArgs << ClangHelpers::clangBuiltinIncludePath().toUtf8(); - clangArguments << "-isystem" << smartArgs.last().constData(); + const auto builtinDir = ClangHelpers::clangBuiltinIncludePath(); + // builtinDir should never be empty, still, let's not add a stray -isystem to the argument list. + if (!builtinDir.isEmpty()) { + smartArgs << builtinDir.toUtf8(); + clangArguments << "-isystem" << smartArgs.last().constData(); + } smartArgs << writeDefinesFile(environment.defines()); clangArguments << "-imacros" << smartArgs.last().constData();