diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aaab077d255da..2ad0a006e0346 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -95,10 +95,10 @@ xpti/ @tovinkere @andykaylor xptifw/ @tovinkere @andykaylor # DPC++ tools -llvm/tools/file-table-tform/ @kbobrovs @AlexeySachkov -llvm/tools/llvm-foreach/ @AlexeySachkov @Fznamznon -llvm/tools/llvm-no-spir-kernel/ @AGindinson @AlexeySachkov -llvm/tools/sycl-post-link/ @kbobrovs @AlexeySachkov +llvm/**/file-table-tform/ @kbobrovs @AlexeySachkov +llvm/**/llvm-foreach/ @AlexeySachkov @Fznamznon +llvm/**/llvm-no-spir-kernel/ @AGindinson @AlexeySachkov +llvm/**/sycl-post-link/ @kbobrovs @AlexeySachkov # Clang offload tools clang/tools/clang-offload-bundler/ @kbobrovs @sndmitriev diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 225a43ae1ad7d..03e363c191e7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,6 +62,14 @@ see [ABI Policy Guide](sycl/doc/ABIPolicyGuide.md) for more information. - For any DPC++-related commit, the `[SYCL]` tag should be present in the commit message title. To a reasonable extent, additional tags can be used to signify the component changed, e.g.: `[PI]`, `[CUDA]`, `[Doc]`. +- For product changes which require modification in tests outside of the current repository + (see [Test DPC++ toolchain](sycl/doc/GetStartedGuide.md#test-dpc-toolchain)), + the commit message should contain the link to corresponding test PR, e.g.: E2E + test changes are available under intel/llvm-test-suite#88 or SYCL + conformance test changes are available under KhronosGroup/SYCL-CTS#65 (see + [Autolinked references and URLs](https://docs.github.com/en/free-pro-team/github/writing-on-github/autolinked-references-and-urls) + for more details). The same message should be present both in commit + message and in PR description. ### Review and acceptance testing diff --git a/buildbot/check.py b/buildbot/check.py index f07b248030a49..70e98c1a701ea 100644 --- a/buildbot/check.py +++ b/buildbot/check.py @@ -49,7 +49,7 @@ def main(): parser.add_argument("-d", "--base-branch", metavar="BASE_BRANCH", help="pull request base branch") parser.add_argument("-r", "--pr-number", metavar="PR_NUM", help="pull request number") parser.add_argument("-w", "--builder-dir", metavar="BUILDER_DIR", - help="builder directory, which is the directory contains source and build directories") + help="builder directory, which is the directory containing source and build directories") parser.add_argument("-s", "--src-dir", metavar="SRC_DIR", help="source directory") parser.add_argument("-o", "--obj-dir", metavar="OBJ_DIR", help="build directory") parser.add_argument("-t", "--test-suite", metavar="TEST_SUITE", default="check-all", help="check-xxx target") diff --git a/buildbot/clang_tidy.py b/buildbot/clang_tidy.py index 1c045aa4cb00a..c9c9eb37d7b68 100644 --- a/buildbot/clang_tidy.py +++ b/buildbot/clang_tidy.py @@ -51,7 +51,7 @@ def main(): help="pull request base branch") parser.add_argument("-r", "--pr-number", metavar="PR_NUM", help="pull request number") parser.add_argument("-w", "--builder-dir", metavar="BUILDER_DIR", required=True, - help="builder directory, which is the directory contains source and build directories") + help="builder directory, which is the directory containing source and build directories") parser.add_argument("-s", "--src-dir", metavar="SRC_DIR", required=True, help="source directory") parser.add_argument("-o", "--obj-dir", metavar="OBJ_DIR", required=True, help="build directory") diff --git a/buildbot/compile.py b/buildbot/compile.py index 01a3936e65e05..53766ada61952 100644 --- a/buildbot/compile.py +++ b/buildbot/compile.py @@ -51,7 +51,7 @@ def main(): parser.add_argument("-d", "--base-branch", metavar="BASE_BRANCH", help="pull request base branch") parser.add_argument("-r", "--pr-number", metavar="PR_NUM", help="pull request number") parser.add_argument("-w", "--builder-dir", metavar="BUILDER_DIR", - help="builder directory, which is the directory contains source and build directories") + help="builder directory, which is the directory containing source and build directories") parser.add_argument("-s", "--src-dir", metavar="SRC_DIR", help="source directory") parser.add_argument("-o", "--obj-dir", metavar="OBJ_DIR", help="build directory") parser.add_argument("-j", "--build-parallelism", metavar="BUILD_PARALLELISM", help="build parallelism") diff --git a/buildbot/configure.py b/buildbot/configure.py index 1e7781c4c6df3..c9be61f91d33a 100644 --- a/buildbot/configure.py +++ b/buildbot/configure.py @@ -123,7 +123,7 @@ def main(): parser.add_argument("-d", "--base-branch", metavar="BASE_BRANCH", help="pull request base branch") parser.add_argument("-r", "--pr-number", metavar="PR_NUM", help="pull request number") parser.add_argument("-w", "--builder-dir", metavar="BUILDER_DIR", - help="builder directory, which is the directory contains source and build directories") + help="builder directory, which is the directory containing source and build directories") # User options parser.add_argument("-s", "--src-dir", metavar="SRC_DIR", help="source directory (autodetected by default)") parser.add_argument("-o", "--obj-dir", metavar="OBJ_DIR", help="build directory. (/build by default)") diff --git a/buildbot/dependency.conf b/buildbot/dependency.conf index a0c8303dde9f4..560645df01304 100644 --- a/buildbot/dependency.conf +++ b/buildbot/dependency.conf @@ -4,8 +4,8 @@ ocl_cpu_rt_ver=2020.11.11.0.04 # https://github.com/intel/llvm/releases/download/2020-WW45/win-oclcpuexp-2020.11.11.0.04_rel.zip ocl_cpu_rt_ver_win=2020.11.11.0.04 # Same GPU driver supports Level Zero and OpenCL -# https://github.com/intel/compute-runtime/releases/tag/20.52.18783 -ocl_gpu_rt_ver=20.52.18783 +# https://github.com/intel/compute-runtime/releases/tag/21.01.18793 +ocl_gpu_rt_ver=21.01.18793 # Same GPU driver supports Level Zero and OpenCL # https://downloadmirror.intel.com/30066/a08/igfx_win10_100.9030.zip ocl_gpu_rt_ver_win=27.20.100.9030 @@ -26,7 +26,7 @@ ocloc_ver_win=27.20.100.8935 [DRIVER VERSIONS] cpu_driver_lin=2020.11.11.0.04 cpu_driver_win=2020.11.11.0.04 -gpu_driver_lin=20.52.18783 +gpu_driver_lin=21.01.18793 gpu_driver_win=27.20.100.9030 fpga_driver_lin=2020.11.11.0.04 fpga_driver_win=2020.11.11.0.04 diff --git a/buildbot/dependency.py b/buildbot/dependency.py index 21ee9258871d5..20ba0fc9041d7 100644 --- a/buildbot/dependency.py +++ b/buildbot/dependency.py @@ -97,7 +97,7 @@ def main(): parser.add_argument("-d", "--base-branch", metavar="BASE_BRANCH", help="pull request base branch") parser.add_argument("-r", "--pr-number", metavar="PR_NUM", help="pull request number") parser.add_argument("-w", "--builder-dir", metavar="BUILDER_DIR", - help="builder directory, which is the directory contains source and build directories") + help="builder directory, which is the directory containing source and build directories") parser.add_argument("-s", "--src-dir", metavar="SRC_DIR", help="source directory") parser.add_argument("-o", "--obj-dir", metavar="OBJ_DIR", required=True, help="build directory") parser.add_argument("-c", "--clean-build", action="store_true", default=False, diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 633655e5e24ab..12d2134026c41 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -22,13 +22,10 @@ #include "ExpandModularHeadersPPCallbacks.h" #include "clang-tidy-config.h" #include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Format/Format.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -43,7 +40,6 @@ #include "clang/Tooling/ReplacementsYaml.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/Process.h" -#include "llvm/Support/Signals.h" #include #include diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp index 3567aac42c062..e1bea430a89a5 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp @@ -10,9 +10,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" -#include "llvm/Support/WithColor.h" #include "llvm/Support/YAMLParser.h" -#include "llvm/Support/raw_ostream.h" namespace clang { namespace tidy { diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index 2c3f51a4034eb..346fa66a662a1 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -23,7 +23,6 @@ #include "clang/AST/Attr.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/DiagnosticRenderer.h" #include "clang/Tooling/Core/Diagnostic.h" @@ -31,7 +30,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" -#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Regex.h" #include @@ -39,6 +37,10 @@ using namespace clang; using namespace tidy; +#ifdef LLVM_CLANG_AST_ATTR_H +//#error +#endif + namespace { class ClangTidyDiagnosticRenderer : public DiagnosticRenderer { public: diff --git a/clang-tools-extra/clang-tidy/ClangTidyModule.h b/clang-tools-extra/clang-tidy/ClangTidyModule.h index 7fd16c2a7b3c7..dd21a8dbc6a43 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyModule.h +++ b/clang-tools-extra/clang-tidy/ClangTidyModule.h @@ -13,9 +13,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include -#include #include -#include namespace clang { namespace tidy { diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index 197552acf927c..472123f8b3068 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -16,7 +16,6 @@ #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Path.h" #include "llvm/Support/YAMLTraits.h" -#include "llvm/Support/raw_ostream.h" #include #define DEBUG_TYPE "clang-tidy-options" diff --git a/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp b/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp index e60332d599a59..b107dd7385c65 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyProfiling.cpp @@ -7,11 +7,9 @@ //===----------------------------------------------------------------------===// #include "ClangTidyProfiling.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" -#include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" #include #include diff --git a/clang-tools-extra/clang-tidy/altera/SingleWorkItemBarrierCheck.cpp b/clang-tools-extra/clang-tidy/altera/SingleWorkItemBarrierCheck.cpp index 759c81c34ca64..521126f990e97 100644 --- a/clang-tools-extra/clang-tidy/altera/SingleWorkItemBarrierCheck.cpp +++ b/clang-tools-extra/clang-tidy/altera/SingleWorkItemBarrierCheck.cpp @@ -57,8 +57,9 @@ void SingleWorkItemBarrierCheck::check(const MatchFinder::MatchResult &Result) { bool IsNDRange = false; if (MatchedDecl->hasAttr()) { const auto *Attribute = MatchedDecl->getAttr(); - if (Attribute->getXDim() > 1 || Attribute->getYDim() > 1 || - Attribute->getZDim() > 1) + if (*Attribute->getXDimVal(*Result.Context) > 1 || + *Attribute->getYDimVal(*Result.Context) > 1 || + *Attribute->getZDimVal(*Result.Context) > 1) IsNDRange = true; } if (IsNDRange) // No warning if kernel is treated as an NDRange. diff --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp index 14a38c09ad9b0..e7c5f0ab05be9 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp @@ -16,6 +16,77 @@ using namespace clang::ast_matchers; namespace clang { +namespace ast_matchers { +AST_POLYMORPHIC_MATCHER_P2(hasAnyArgumentWithParam, + AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, + CXXConstructExpr), + internal::Matcher, ArgMatcher, + internal::Matcher, ParamMatcher) { + BoundNodesTreeBuilder Result; + // The first argument of an overloaded member operator is the implicit object + // argument of the method which should not be matched against a parameter, so + // we skip over it here. + BoundNodesTreeBuilder Matches; + unsigned ArgIndex = cxxOperatorCallExpr(callee(cxxMethodDecl())) + .matches(Node, Finder, &Matches) + ? 1 + : 0; + int ParamIndex = 0; + for (; ArgIndex < Node.getNumArgs(); ++ArgIndex) { + BoundNodesTreeBuilder ArgMatches(*Builder); + if (ArgMatcher.matches(*(Node.getArg(ArgIndex)->IgnoreParenCasts()), Finder, + &ArgMatches)) { + BoundNodesTreeBuilder ParamMatches(ArgMatches); + if (expr(anyOf(cxxConstructExpr(hasDeclaration(cxxConstructorDecl( + hasParameter(ParamIndex, ParamMatcher)))), + callExpr(callee(functionDecl( + hasParameter(ParamIndex, ParamMatcher)))))) + .matches(Node, Finder, &ParamMatches)) { + Result.addMatch(ParamMatches); + *Builder = std::move(Result); + return true; + } + } + ++ParamIndex; + } + return false; +} + +AST_MATCHER(Expr, usedInBooleanContext) { + const char *ExprName = "__booleanContextExpr"; + auto Result = + expr(expr().bind(ExprName), + anyOf(hasParent(varDecl(hasType(booleanType()))), + hasParent(cxxConstructorDecl( + hasAnyConstructorInitializer(cxxCtorInitializer( + withInitializer(expr(equalsBoundNode(ExprName))), + forField(hasType(booleanType())))))), + hasParent(fieldDecl(hasType(booleanType()))), + hasParent(stmt(anyOf( + explicitCastExpr(hasDestinationType(booleanType())), + ifStmt(hasCondition(expr(equalsBoundNode(ExprName)))), + doStmt(hasCondition(expr(equalsBoundNode(ExprName)))), + whileStmt(hasCondition(expr(equalsBoundNode(ExprName)))), + forStmt(hasCondition(expr(equalsBoundNode(ExprName)))), + conditionalOperator( + hasCondition(expr(equalsBoundNode(ExprName)))), + parenListExpr(hasParent(varDecl(hasType(booleanType())))), + parenExpr(hasParent( + explicitCastExpr(hasDestinationType(booleanType())))), + returnStmt(forFunction(returns(booleanType()))), + cxxUnresolvedConstructExpr(hasType(booleanType())), + callExpr(hasAnyArgumentWithParam( + expr(equalsBoundNode(ExprName)), + parmVarDecl(hasType(booleanType())))), + binaryOperator(hasAnyOperatorName("&&", "||")), + unaryOperator(hasOperatorName("!")).bind("NegOnSize")))))) + .matches(Node, Finder, Builder); + Builder->removeBindings([ExprName](const BoundNodesMap &Nodes) { + return Nodes.getNode(ExprName).getNodeKind().isNone(); + }); + return Result; +} +} // namespace ast_matchers namespace tidy { namespace readability { @@ -26,18 +97,27 @@ ContainerSizeEmptyCheck::ContainerSizeEmptyCheck(StringRef Name, : ClangTidyCheck(Name, Context) {} void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { - const auto ValidContainer = qualType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom( - namedDecl( - has(cxxMethodDecl( - isConst(), parameterCountIs(0), isPublic(), - hasName("size"), - returns(qualType(isInteger(), unless(booleanType())))) - .bind("size")), - has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(), - hasName("empty"), returns(booleanType())) - .bind("empty"))) - .bind("container"))))))); + const auto ValidContainerRecord = cxxRecordDecl(isSameOrDerivedFrom( + namedDecl( + has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(), + hasName("size"), + returns(qualType(isInteger(), unless(booleanType()), + unless(elaboratedType())))) + .bind("size")), + has(cxxMethodDecl(isConst(), parameterCountIs(0), isPublic(), + hasName("empty"), returns(booleanType())) + .bind("empty"))) + .bind("container"))); + + const auto ValidContainerNonTemplateType = + qualType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(ValidContainerRecord)))); + const auto ValidContainerTemplateType = + qualType(hasUnqualifiedDesugaredType(templateSpecializationType( + hasDeclaration(classTemplateDecl(has(ValidContainerRecord)))))); + + const auto ValidContainer = qualType( + anyOf(ValidContainerNonTemplateType, ValidContainerTemplateType)); const auto WrongUse = traverse( TK_AsIs, @@ -52,18 +132,34 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { anyOf(hasParent( unaryOperator(hasOperatorName("!")).bind("NegOnSize")), anything()))), - hasParent(explicitCastExpr(hasDestinationType(booleanType()))))); + usedInBooleanContext())); Finder->addMatcher( - cxxMemberCallExpr(on(expr(anyOf(hasType(ValidContainer), + cxxMemberCallExpr(unless(isInTemplateInstantiation()), + on(expr(anyOf(hasType(ValidContainer), hasType(pointsTo(ValidContainer)), - hasType(references(ValidContainer))))), + hasType(references(ValidContainer)))) + .bind("MemberCallObject")), callee(cxxMethodDecl(hasName("size"))), WrongUse, unless(hasAncestor(cxxMethodDecl( ofClass(equalsBoundNode("container")))))) .bind("SizeCallExpr"), this); + Finder->addMatcher( + callExpr(has(cxxDependentScopeMemberExpr( + hasObjectExpression( + expr(anyOf(hasType(ValidContainer), + hasType(pointsTo(ValidContainer)), + hasType(references(ValidContainer)))) + .bind("MemberCallObject")), + hasMemberName("size"))), + WrongUse, + unless(hasAncestor( + cxxMethodDecl(ofClass(equalsBoundNode("container")))))) + .bind("SizeCallExpr"), + this); + // Empty constructor matcher. const auto DefaultConstructor = cxxConstructExpr( hasDeclaration(cxxConstructorDecl(isDefaultConstructor()))); @@ -72,12 +168,11 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { ignoringImpCasts(stringLiteral(hasSize(0))), ignoringImpCasts(cxxBindTemporaryExpr(has(DefaultConstructor))), ignoringImplicit(DefaultConstructor), - cxxConstructExpr( - hasDeclaration(cxxConstructorDecl(isCopyConstructor())), - has(expr(ignoringImpCasts(DefaultConstructor)))), - cxxConstructExpr( - hasDeclaration(cxxConstructorDecl(isMoveConstructor())), - has(expr(ignoringImpCasts(DefaultConstructor))))); + cxxConstructExpr(hasDeclaration(cxxConstructorDecl(isCopyConstructor())), + has(expr(ignoringImpCasts(DefaultConstructor)))), + cxxConstructExpr(hasDeclaration(cxxConstructorDecl(isMoveConstructor())), + has(expr(ignoringImpCasts(DefaultConstructor)))), + cxxUnresolvedConstructExpr(argumentCountIs(0))); // Match the object being compared. const auto STLArg = anyOf(unaryOperator( @@ -87,6 +182,7 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { expr(hasType(ValidContainer)).bind("STLObject")); Finder->addMatcher( cxxOperatorCallExpr( + unless(isInTemplateInstantiation()), hasAnyOverloadedOperatorName("==", "!="), anyOf(allOf(hasArgument(0, WrongComparend), hasArgument(1, STLArg)), allOf(hasArgument(0, STLArg), hasArgument(1, WrongComparend))), @@ -94,24 +190,33 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { cxxMethodDecl(ofClass(equalsBoundNode("container")))))) .bind("BinCmp"), this); + Finder->addMatcher( + binaryOperator(hasAnyOperatorName("==", "!="), + anyOf(allOf(hasLHS(WrongComparend), hasRHS(STLArg)), + allOf(hasLHS(STLArg), hasRHS(WrongComparend))), + unless(hasAncestor( + cxxMethodDecl(ofClass(equalsBoundNode("container")))))) + .bind("BinCmp"), + this); } void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) { - const auto *MemberCall = - Result.Nodes.getNodeAs("SizeCallExpr"); + const auto *MemberCall = Result.Nodes.getNodeAs("SizeCallExpr"); + const auto *MemberCallObject = + Result.Nodes.getNodeAs("MemberCallObject"); const auto *BinCmp = Result.Nodes.getNodeAs("BinCmp"); + const auto *BinCmpTempl = Result.Nodes.getNodeAs("BinCmp"); const auto *BinaryOp = Result.Nodes.getNodeAs("SizeBinaryOp"); const auto *Pointee = Result.Nodes.getNodeAs("Pointee"); const auto *E = - MemberCall - ? MemberCall->getImplicitObjectArgument() + MemberCallObject + ? MemberCallObject : (Pointee ? Pointee : Result.Nodes.getNodeAs("STLObject")); FixItHint Hint; std::string ReplacementText = std::string( Lexer::getSourceText(CharSourceRange::getTokenRange(E->getSourceRange()), *Result.SourceManager, getLangOpts())); - if (BinCmp && IsBinaryOrTernary(E)) { - // Not just a DeclRefExpr, so parenthesize to be on the safe side. + if (IsBinaryOrTernary(E) || isa(E)) { ReplacementText = "(" + ReplacementText + ")"; } if (E->getType()->isPointerType()) @@ -125,7 +230,13 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) { } Hint = FixItHint::CreateReplacement(BinCmp->getSourceRange(), ReplacementText); - } else if (BinaryOp) { // Determine the correct transformation. + } else if (BinCmpTempl) { + if (BinCmpTempl->getOpcode() == BinaryOperatorKind::BO_NE) { + ReplacementText = "!" + ReplacementText; + } + Hint = FixItHint::CreateReplacement(BinCmpTempl->getSourceRange(), + ReplacementText); + } else if (BinaryOp) { // Determine the correct transformation. bool Negation = false; const bool ContainerIsLHS = !llvm::isa(BinaryOp->getLHS()->IgnoreImpCasts()); @@ -195,15 +306,17 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) { "!" + ReplacementText); } - if (MemberCall) { - diag(MemberCall->getBeginLoc(), - "the 'empty' method should be used to check " - "for emptiness instead of 'size'") + auto WarnLoc = MemberCall ? MemberCall->getBeginLoc() : SourceLocation{}; + + if (WarnLoc.isValid()) { + diag(WarnLoc, "the 'empty' method should be used to check " + "for emptiness instead of 'size'") << Hint; } else { - diag(BinCmp->getBeginLoc(), - "the 'empty' method should be used to check " - "for emptiness instead of comparing to an empty object") + WarnLoc = BinCmpTempl ? BinCmpTempl->getBeginLoc() + : (BinCmp ? BinCmp->getBeginLoc() : SourceLocation{}); + diag(WarnLoc, "the 'empty' method should be used to check " + "for emptiness instead of comparing to an empty object") << Hint; } diff --git a/clang-tools-extra/clangd/CMakeLists.txt b/clang-tools-extra/clangd/CMakeLists.txt index 919457f216c15..9e62e09480274 100644 --- a/clang-tools-extra/clangd/CMakeLists.txt +++ b/clang-tools-extra/clangd/CMakeLists.txt @@ -14,9 +14,12 @@ if (NOT DEFINED CLANGD_BUILD_XPC) unset(CLANGD_BUILD_XPC_DEFAULT) endif () +option(CLANGD_MALLOC_TRIM "Call malloc_trim(3) periodically in Clangd. (only takes effect when using glibc)" ON) + llvm_canonicalize_cmake_booleans( CLANGD_BUILD_XPC CLANGD_ENABLE_REMOTE + CLANGD_MALLOC_TRIM LLVM_ENABLE_ZLIB ) diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index b32c9e13973b6..c606ccae4fdc0 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -178,6 +178,7 @@ class ClangdLSPServer::MessageHandler : public Transport::MessageHandler { } else if (auto Handler = Notifications.lookup(Method)) { Handler(std::move(Params)); Server.maybeExportMemoryProfile(); + Server.maybeCleanupMemory(); } else { log("unhandled notification {0}", Method); } @@ -453,6 +454,7 @@ void ClangdLSPServer::callRaw(StringRef Method, llvm::json::Value Params, void ClangdLSPServer::notify(llvm::StringRef Method, llvm::json::Value Params) { log("--> {0}", Method); + maybeCleanupMemory(); std::lock_guard Lock(TranspWriter); Transp.notify(Method, std::move(Params)); } @@ -1283,13 +1285,7 @@ void ClangdLSPServer::publishDiagnostics( } void ClangdLSPServer::maybeExportMemoryProfile() { - if (!trace::enabled()) - return; - // Profiling might be expensive, so we throttle it to happen once every 5 - // minutes. - static constexpr auto ProfileInterval = std::chrono::minutes(5); - auto Now = std::chrono::steady_clock::now(); - if (Now < NextProfileTime) + if (!trace::enabled() || !ShouldProfile()) return; static constexpr trace::Metric MemoryUsage( @@ -1298,7 +1294,12 @@ void ClangdLSPServer::maybeExportMemoryProfile() { MemoryTree MT; profile(MT); record(MT, "clangd_lsp_server", MemoryUsage); - NextProfileTime = Now + ProfileInterval; +} + +void ClangdLSPServer::maybeCleanupMemory() { + if (!Opts.MemoryCleanup || !ShouldCleanupMemory()) + return; + Opts.MemoryCleanup(); } // FIXME: This function needs to be properly tested. @@ -1458,10 +1459,15 @@ void ClangdLSPServer::onAST(const ASTParams &Params, ClangdLSPServer::ClangdLSPServer(class Transport &Transp, const ThreadsafeFS &TFS, const ClangdLSPServer::Options &Opts) - : BackgroundContext(Context::current().clone()), Transp(Transp), + : ShouldProfile(/*Period=*/std::chrono::minutes(5), + /*Delay=*/std::chrono::minutes(1)), + ShouldCleanupMemory(/*Period=*/std::chrono::minutes(1), + /*Delay=*/std::chrono::minutes(1)), + BackgroundContext(Context::current().clone()), Transp(Transp), MsgHandler(new MessageHandler(*this)), TFS(TFS), SupportedSymbolKinds(defaultSymbolKinds()), SupportedCompletionItemKinds(defaultCompletionItemKinds()), Opts(Opts) { + // clang-format off MsgHandler->bind("initialize", &ClangdLSPServer::onInitialize); MsgHandler->bind("initialized", &ClangdLSPServer::onInitialized); @@ -1506,9 +1512,6 @@ ClangdLSPServer::ClangdLSPServer(class Transport &Transp, if (Opts.FoldingRanges) MsgHandler->bind("textDocument/foldingRange", &ClangdLSPServer::onFoldingRange); // clang-format on - - // Delay first profile until we've finished warming up. - NextProfileTime = std::chrono::steady_clock::now() + std::chrono::minutes(1); } ClangdLSPServer::~ClangdLSPServer() { @@ -1621,6 +1624,10 @@ void ClangdLSPServer::onDiagnosticsReady(PathRef File, llvm::StringRef Version, void ClangdLSPServer::onBackgroundIndexProgress( const BackgroundQueue::Stats &Stats) { static const char ProgressToken[] = "backgroundIndexProgress"; + + // The background index did some work, maybe we need to cleanup + maybeCleanupMemory(); + std::lock_guard Lock(BackgroundIndexProgressMutex); auto NotifyProgress = [this](const BackgroundQueue::Stats &Stats) { diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h index e65fc0e8a0064..a41bc5666af33 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -19,6 +19,7 @@ #include "support/Context.h" #include "support/MemoryTree.h" #include "support/Path.h" +#include "support/Threading.h" #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" @@ -48,6 +49,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks { llvm::Optional CompileCommandsDir; /// The offset-encoding to use, or None to negotiate it over LSP. llvm::Optional Encoding; + /// If set, periodically called to release memory. + /// Consider malloc_trim(3) + std::function MemoryCleanup = nullptr; /// Per-feature options. Generally ClangdServer lets these vary /// per-request, but LSP allows limited/no customizations. @@ -183,10 +187,12 @@ class ClangdLSPServer : private ClangdServer::Callbacks { /// Runs profiling and exports memory usage metrics if tracing is enabled and /// profiling hasn't happened recently. void maybeExportMemoryProfile(); + PeriodicThrottler ShouldProfile; - /// Timepoint until which profiling is off. It is used to throttle profiling - /// requests. - std::chrono::steady_clock::time_point NextProfileTime; + /// Run the MemoryCleanup callback if it's time. + /// This method is thread safe. + void maybeCleanupMemory(); + PeriodicThrottler ShouldCleanupMemory; /// Since initialization of CDBs and ClangdServer is done lazily, the /// following context captures the one used while creating ClangdLSPServer and diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 8b0d0591abe70..b760b31c0b87b 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -621,7 +621,7 @@ void ClangdServer::typeHierarchy(PathRef File, Position Pos, int Resolve, File)); }; - WorkScheduler.runWithAST("Type Hierarchy", File, std::move(Action)); + WorkScheduler.runWithAST("TypeHierarchy", File, std::move(Action)); } void ClangdServer::resolveTypeHierarchy( @@ -642,7 +642,7 @@ void ClangdServer::prepareCallHierarchy( return CB(InpAST.takeError()); CB(clangd::prepareCallHierarchy(InpAST->AST, Pos, File)); }; - WorkScheduler.runWithAST("Call Hierarchy", File, std::move(Action)); + WorkScheduler.runWithAST("CallHierarchy", File, std::move(Action)); } void ClangdServer::incomingCalls( @@ -678,7 +678,7 @@ void ClangdServer::documentSymbols(llvm::StringRef File, return CB(InpAST.takeError()); CB(clangd::getDocumentSymbols(InpAST->AST)); }; - WorkScheduler.runWithAST("documentSymbols", File, std::move(Action), + WorkScheduler.runWithAST("DocumentSymbols", File, std::move(Action), TUScheduler::InvalidateOnUpdate); } @@ -690,7 +690,7 @@ void ClangdServer::foldingRanges(llvm::StringRef File, return CB(InpAST.takeError()); CB(clangd::getFoldingRanges(InpAST->AST)); }; - WorkScheduler.runWithAST("foldingRanges", File, std::move(Action), + WorkScheduler.runWithAST("FoldingRanges", File, std::move(Action), TUScheduler::InvalidateOnUpdate); } diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index cc6b5dbc9904f..ebdbd56c286ac 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -182,12 +182,18 @@ struct CompletionCandidate { // strings (literal or URI) mapping to the same file. We still want to // bundle those, so we must resolve the header to be included here. std::string HeaderForHash; - if (Inserter) - if (auto Header = headerToInsertIfAllowed(Opts)) - if (auto HeaderFile = toHeaderFile(*Header, FileName)) + if (Inserter) { + if (auto Header = headerToInsertIfAllowed(Opts)) { + if (auto HeaderFile = toHeaderFile(*Header, FileName)) { if (auto Spelled = Inserter->calculateIncludePath(*HeaderFile, FileName)) HeaderForHash = *Spelled; + } else { + vlog("Code completion header path manipulation failed {0}", + HeaderFile.takeError()); + } + } + } llvm::SmallString<256> Scratch; if (IndexResult) { diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp index 8f1b3f3a1aae5..12698b42ef3e6 100644 --- a/clang-tools-extra/clangd/DumpAST.cpp +++ b/clang-tools-extra/clangd/DumpAST.cpp @@ -143,7 +143,6 @@ class DumpVisitor : public RecursiveASTVisitor { TEMPLATE_ARGUMENT_KIND(Declaration); TEMPLATE_ARGUMENT_KIND(Template); TEMPLATE_ARGUMENT_KIND(TemplateExpansion); - TEMPLATE_ARGUMENT_KIND(UncommonValue); #undef TEMPLATE_ARGUMENT_KIND } llvm_unreachable("Unhandled ArgKind enum"); diff --git a/clang-tools-extra/clangd/Features.inc.in b/clang-tools-extra/clangd/Features.inc.in index 6797232ddac7c..c21d2b1455710 100644 --- a/clang-tools-extra/clangd/Features.inc.in +++ b/clang-tools-extra/clangd/Features.inc.in @@ -1,2 +1,3 @@ #define CLANGD_BUILD_XPC @CLANGD_BUILD_XPC@ #define CLANGD_ENABLE_REMOTE @CLANGD_ENABLE_REMOTE@ +#define CLANGD_MALLOC_TRIM @CLANGD_MALLOC_TRIM@ diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index c5c7d71be6618..3afd655226805 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -1069,7 +1069,6 @@ class ExplicitReferenceCollector case TemplateArgument::Pack: case TemplateArgument::Type: case TemplateArgument::Expression: - case TemplateArgument::UncommonValue: break; // Handled by VisitType and VisitExpression. }; return RecursiveASTVisitor::TraverseTemplateArgumentLoc(A); diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp index 41b549cefc7cc..86375fa11d3b1 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp @@ -511,11 +511,14 @@ void DirectoryBasedGlobalCompilationDatabase::broadcastCDB( // Given that we know that CDBs have been moved/generated, don't trust caches. // (This should be rare, so it's OK to add a little latency). constexpr auto IgnoreCache = std::chrono::steady_clock::time_point::max(); - for (DirectoryCache *Dir : getDirectoryCaches(FileAncestors)) { + auto DirectoryCaches = getDirectoryCaches(FileAncestors); + assert(DirectoryCaches.size() == FileAncestors.size()); + for (unsigned I = 0; I < DirectoryCaches.size(); ++I) { bool ShouldBroadcast = false; - if (Dir->get(Opts.TFS, ShouldBroadcast, /*FreshTime=*/IgnoreCache, - /*FreshTimeMissing=*/IgnoreCache)) - DirectoryHasCDB.find(Dir->Path)->setValue(true); + if (DirectoryCaches[I]->get(Opts.TFS, ShouldBroadcast, + /*FreshTime=*/IgnoreCache, + /*FreshTimeMissing=*/IgnoreCache)) + DirectoryHasCDB.find(FileAncestors[I])->setValue(true); } std::vector GovernedFiles; diff --git a/clang-tools-extra/clangd/JSONTransport.cpp b/clang-tools-extra/clangd/JSONTransport.cpp index eb5a83882b2bd..662e5df4e27bf 100644 --- a/clang-tools-extra/clangd/JSONTransport.cpp +++ b/clang-tools-extra/clangd/JSONTransport.cpp @@ -126,13 +126,13 @@ class JSONTransport : public Transport { bool handleMessage(llvm::json::Value Message, MessageHandler &Handler); // Writes outgoing message to Out stream. void sendMessage(llvm::json::Value Message) { - std::string S; - llvm::raw_string_ostream OS(S); + OutputBuffer.clear(); + llvm::raw_svector_ostream OS(OutputBuffer); OS << llvm::formatv(Pretty ? "{0:2}" : "{0}", Message); - OS.flush(); - Out << "Content-Length: " << S.size() << "\r\n\r\n" << S; + Out << "Content-Length: " << OutputBuffer.size() << "\r\n\r\n" + << OutputBuffer; Out.flush(); - vlog(">>> {0}\n", S); + vlog(">>> {0}\n", OutputBuffer); } // Read raw string messages from input stream. @@ -143,6 +143,7 @@ class JSONTransport : public Transport { llvm::Optional readDelimitedMessage(); llvm::Optional readStandardMessage(); + llvm::SmallVector OutputBuffer; std::FILE *In; llvm::raw_ostream &Out; llvm::raw_ostream &InMirror; diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp index 813a000b41a5f..7a858664faa5a 100644 --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -1220,7 +1220,7 @@ std::string renderTUAction(const PreambleAction PA, const ASTAction &AA) { } if (Result.empty()) return "idle"; - return llvm::join(Result, ","); + return llvm::join(Result, ", "); } } // namespace diff --git a/clang-tools-extra/clangd/index/Merge.cpp b/clang-tools-extra/clangd/index/Merge.cpp index 97babacf2b38e..f66f47499624a 100644 --- a/clang-tools-extra/clangd/index/Merge.cpp +++ b/clang-tools-extra/clangd/index/Merge.cpp @@ -76,7 +76,13 @@ void MergedIndex::lookup( Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); }); auto RemainingIDs = Req.IDs; + auto DynamicContainsFile = Dynamic->indexedFiles(); Static->lookup(Req, [&](const Symbol &S) { + // We expect the definition to see the canonical declaration, so it seems + // to be enough to check only the definition if it exists. + if (DynamicContainsFile(S.Definition ? S.Definition.FileURI + : S.CanonicalDeclaration.FileURI)) + return; const Symbol *Sym = B.find(S.ID); RemainingIDs.erase(S.ID); if (!Sym) diff --git a/clang-tools-extra/clangd/index/remote/Client.cpp b/clang-tools-extra/clangd/index/remote/Client.cpp index a153a8812baff..b09dbf915e462 100644 --- a/clang-tools-extra/clangd/index/remote/Client.cpp +++ b/clang-tools-extra/clangd/index/remote/Client.cpp @@ -152,8 +152,7 @@ class IndexClient : public clangd::SymbolIndex { }); } - llvm::unique_function - indexedFiles() const override { + llvm::unique_function indexedFiles() const { // FIXME: For now we always return "false" regardless of whether the file // was indexed or not. A possible implementation could be based on // the idea that we do not want to send a request at every diff --git a/clang-tools-extra/clangd/support/Threading.cpp b/clang-tools-extra/clangd/support/Threading.cpp index 5f95888ae3e2d..7f3bd62be306c 100644 --- a/clang-tools-extra/clangd/support/Threading.cpp +++ b/clang-tools-extra/clangd/support/Threading.cpp @@ -116,5 +116,17 @@ void wait(std::unique_lock &Lock, std::condition_variable &CV, CV.wait_until(Lock, D.time()); } +bool PeriodicThrottler::operator()() { + Rep Now = Stopwatch::now().time_since_epoch().count(); + Rep OldNext = Next.load(std::memory_order_acquire); + if (Now < OldNext) + return false; + // We're ready to run (but may be racing other threads). + // Work out the updated target time, and run if we successfully bump it. + Rep NewNext = Now + Period; + return Next.compare_exchange_strong(OldNext, NewNext, + std::memory_order_acq_rel); +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/support/Threading.h b/clang-tools-extra/clangd/support/Threading.h index 5155ac193fd18..da9e3b8ea8b68 100644 --- a/clang-tools-extra/clangd/support/Threading.h +++ b/clang-tools-extra/clangd/support/Threading.h @@ -169,6 +169,35 @@ template class Memoize { } }; +/// Used to guard an operation that should run at most every N seconds. +/// +/// Usage: +/// mutable PeriodicThrottler ShouldLog(std::chrono::seconds(1)); +/// void calledFrequently() { +/// if (ShouldLog()) +/// log("this is not spammy"); +/// } +/// +/// This class is threadsafe. If multiple threads are involved, then the guarded +/// operation still needs to be threadsafe! +class PeriodicThrottler { + using Stopwatch = std::chrono::steady_clock; + using Rep = Stopwatch::duration::rep; + + Rep Period; + std::atomic Next; + +public: + /// If Period is zero, the throttler will return true every time. + PeriodicThrottler(Stopwatch::duration Period, Stopwatch::duration Delay = {}) + : Period(Period.count()), + Next((Stopwatch::now() + Delay).time_since_epoch().count()) {} + + /// Returns whether the operation should run at this time. + /// operator() is safe to call concurrently. + bool operator()(); +}; + } // namespace clangd } // namespace clang #endif diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 331241115302b..d2c52cf61c53b 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -50,6 +50,10 @@ #include #endif +#ifdef __GLIBC__ +#include +#endif + namespace clang { namespace clangd { @@ -497,6 +501,29 @@ opt CollectMainFileRefs{ init(ClangdServer::Options().CollectMainFileRefs), }; +#if defined(__GLIBC__) && CLANGD_MALLOC_TRIM +opt EnableMallocTrim{ + "malloc-trim", + cat(Misc), + desc("Release memory periodically via malloc_trim(3)."), + init(true), +}; + +std::function getMemoryCleanupFunction() { + if (!EnableMallocTrim) + return nullptr; + // Leave a few MB at the top of the heap: it is insignificant + // and will most likely be needed by the main thread + constexpr size_t MallocTrimPad = 20'000'000; + return []() { + if (malloc_trim(MallocTrimPad)) + vlog("Released memory via malloc_trim"); + }; +} +#else +std::function getMemoryCleanupFunction() { return nullptr; } +#endif + #if CLANGD_ENABLE_REMOTE opt RemoteIndexAddress{ "remote-index-address", @@ -797,6 +824,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var Opts.BuildRecoveryAST = RecoveryAST; Opts.PreserveRecoveryASTType = RecoveryASTType; Opts.FoldingRanges = FoldingRanges; + Opts.MemoryCleanup = getMemoryCleanupFunction(); Opts.CodeComplete.IncludeIneligibleResults = IncludeIneligibleResults; Opts.CodeComplete.Limit = LimitResults; diff --git a/clang-tools-extra/clangd/unittests/IndexTests.cpp b/clang-tools-extra/clangd/unittests/IndexTests.cpp index 8efc637d1250b..ce4845e3e1446 100644 --- a/clang-tools-extra/clangd/unittests/IndexTests.cpp +++ b/clang-tools-extra/clangd/unittests/IndexTests.cpp @@ -290,6 +290,40 @@ TEST(MergeIndexTest, Lookup) { EXPECT_THAT(lookup(M, {}), UnorderedElementsAre()); } +TEST(MergeIndexTest, LookupRemovedDefinition) { + FileIndex DynamicIndex, StaticIndex; + MergedIndex Merge(&DynamicIndex, &StaticIndex); + + const char *HeaderCode = "class Foo;"; + auto HeaderSymbols = TestTU::withHeaderCode(HeaderCode).headerSymbols(); + auto Foo = findSymbol(HeaderSymbols, "Foo"); + + // Build static index for test.cc with Foo definition + TestTU Test; + Test.HeaderCode = HeaderCode; + Test.Code = "class Foo {};"; + Test.Filename = "test.cc"; + auto AST = Test.build(); + StaticIndex.updateMain(testPath(Test.Filename), AST); + + // Remove Foo definition from test.cc, i.e. build dynamic index for test.cc + // without Foo definition. + Test.Code = "class Foo;"; + AST = Test.build(); + DynamicIndex.updateMain(testPath(Test.Filename), AST); + + // Merged index should not return the symbol definition if this definition + // location is inside a file from the dynamic index. + LookupRequest LookupReq; + LookupReq.IDs = {Foo.ID}; + unsigned SymbolCounter = 0; + Merge.lookup(LookupReq, [&](const Symbol &Sym) { + ++SymbolCounter; + EXPECT_FALSE(Sym.Definition); + }); + EXPECT_EQ(SymbolCounter, 1u); +} + TEST(MergeIndexTest, FuzzyFind) { auto I = MemIndex::build(generateSymbols({"ns::A", "ns::B"}), RefSlab(), RelationSlab()), diff --git a/clang-tools-extra/clangd/unittests/support/ThreadingTests.cpp b/clang-tools-extra/clangd/unittests/support/ThreadingTests.cpp index e265ad2eabeae..87002d3cfa86a 100644 --- a/clang-tools-extra/clangd/unittests/support/ThreadingTests.cpp +++ b/clang-tools-extra/clangd/unittests/support/ThreadingTests.cpp @@ -10,6 +10,7 @@ #include "llvm/ADT/DenseMap.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include #include namespace clang { @@ -121,5 +122,25 @@ TEST_F(ThreadingTest, MemoizeDeterministic) { ASSERT_THAT(ValueA.load(), testing::AnyOf('A', 'B')); } +// It's hard to write a real test of this class, std::chrono is awkward to mock. +// But test some degenerate cases at least. +TEST(PeriodicThrottlerTest, Minimal) { + PeriodicThrottler Once(std::chrono::hours(24)); + EXPECT_TRUE(Once()); + EXPECT_FALSE(Once()); + EXPECT_FALSE(Once()); + + PeriodicThrottler Later(std::chrono::hours(24), + /*Delay=*/std::chrono::hours(24)); + EXPECT_FALSE(Later()); + EXPECT_FALSE(Later()); + EXPECT_FALSE(Later()); + + PeriodicThrottler Always(std::chrono::seconds(0)); + EXPECT_TRUE(Always()); + EXPECT_TRUE(Always()); + EXPECT_TRUE(Always()); +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 450b80fd45814..2960aad5a5569 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -47,7 +47,17 @@ Major New Features Improvements to clangd ---------------------- -The improvements are... +- clangd's memory usage is significantly reduced on most Linux systems. + In particular, memory usage should not increase dramatically over time. + + The standard allocator on most systems is glibc's ptmalloc2, and it creates + disproportionately large heaps when handling clangd's allocation patterns. + By default, clangd will now periodically call ``malloc_trim`` to release free + pages on glibc systems. + + Users of other allocators (such as ``jemalloc`` or ``tcmalloc``) on glibc + systems can disable this using ``--malloc_trim=0`` or the CMake flag + ``-DCLANGD_MALLOC_TRIM=0``. Improvements to clang-doc ------------------------- diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp index 9100559233e3c..4fe75f46932d7 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s readability-container-size-empty %t +// RUN: %check_clang_tidy %s readability-container-size-empty %t -- -- -fno-delayed-template-parsing namespace std { template struct vector { @@ -96,6 +96,11 @@ class Container4 { bool empty() const { return *this == Container4(); } }; +struct Lazy { + constexpr unsigned size() const { return 0; } + constexpr bool empty() const { return true; } +}; + std::string s_func() { return std::string(); } @@ -440,6 +445,43 @@ bool returnsBool() { // CHECK-FIXES: {{^ }}return !derived.empty(); } +class ConstructWithBoolField { + bool B; +public: + ConstructWithBoolField(const std::vector &C) : B(C.size()) {} +// CHECK-MESSAGES: :[[@LINE-1]]:57: warning: the 'empty' method should be used +// CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here +// CHECK-FIXES: {{^ }}ConstructWithBoolField(const std::vector &C) : B(!C.empty()) {} +}; + +struct StructWithNSDMI { + std::vector C; + bool B = C.size(); +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: the 'empty' method should be used +// CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here +// CHECK-FIXES: {{^ }}bool B = !C.empty(); +}; + +int func(const std::vector &C) { + return C.size() ? 0 : 1; +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used +// CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here +// CHECK-FIXES: {{^ }}return !C.empty() ? 0 : 1; +} + +constexpr Lazy L; +static_assert(!L.size(), ""); +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: the 'empty' method should be used +// CHECK-MESSAGES: :101:18: note: method 'Lazy'::empty() defined here +// CHECK-FIXES: {{^}}static_assert(L.empty(), ""); + +struct StructWithLazyNoexcept { + void func() noexcept(L.size()); +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: the 'empty' method should be used +// CHECK-MESSAGES: :101:18: note: method 'Lazy'::empty() defined here +// CHECK-FIXES: {{^ }}void func() noexcept(!L.empty()); +}; + #define CHECKSIZE(x) if (x.size()) {} // CHECK-FIXES: #define CHECKSIZE(x) if (x.size()) {} @@ -483,3 +525,177 @@ void g() { f(); f(); } + +template +bool neverInstantiatedTemplate() { + std::vector v; + if (v.size()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (!v.empty()){{$}} + + if (v == std::vector()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of comparing to an empty object [readability-container-size-empty] + // CHECK-FIXES: {{^ }}if (v.empty()){{$}} + // CHECK-FIXES-NEXT: ; + if (v.size() == 0) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (v.empty()){{$}} + if (v.size() != 0) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (!v.empty()){{$}} + if (v.size() < 1) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (v.empty()){{$}} + if (v.size() > 0) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (!v.empty()){{$}} + if (v.size() == 1) + ; + if (v.size() != 1) + ; + if (v.size() == 2) + ; + if (v.size() != 2) + ; + + if (static_cast(v.size())) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:25: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (static_cast(!v.empty())){{$}} + if (v.size() && false) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (!v.empty() && false){{$}} + if (!v.size()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty] + // CHECK-MESSAGES: :9:8: note: method 'vector'::empty() defined here + // CHECK-FIXES: {{^ }}if (v.empty()){{$}} + + TemplatedContainer templated_container; + if (templated_container.size()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}} + if (templated_container != TemplatedContainer()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}if (!templated_container.empty()){{$}} + // CHECK-FIXES-NEXT: ; + while (templated_container.size()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}while (!templated_container.empty()){{$}} + + do { + } + while (templated_container.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}while (!templated_container.empty()); + + for (; templated_container.size();) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}for (; !templated_container.empty();){{$}} + + if (true && templated_container.size()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}if (true && !templated_container.empty()){{$}} + + if (true || templated_container.size()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}if (true || !templated_container.empty()){{$}} + + if (!templated_container.size()) + ; + // CHECK-MESSAGES: :[[@LINE-2]]:8: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}if (templated_container.empty()){{$}} + + bool b1 = templated_container.size(); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}bool b1 = !templated_container.empty(); + + bool b2(templated_container.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}bool b2(!templated_container.empty()); + + auto b3 = static_cast(templated_container.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}auto b3 = static_cast(!templated_container.empty()); + + auto b4 = (bool)templated_container.size(); + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}auto b4 = (bool)!templated_container.empty(); + + auto b5 = bool(templated_container.size()); + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}auto b5 = bool(!templated_container.empty()); + + takesBool(templated_container.size()); + // We don't detect this one because we don't know the parameter of takesBool + // until the type of templated_container.size() is known + + return templated_container.size(); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: the 'empty' method should be used + // CHECK-MESSAGES: :44:8: note: method 'TemplatedContainer'::empty() defined here + // CHECK-FIXES: {{^ }}return !templated_container.empty(); +} + +template +void instantiatedTemplateWithSizeCall() { + TypeRequiresSize t; + // The instantiation of the template with std::vector should not + // result in changing the template, because we don't know that + // TypeRequiresSize generally has `.empty()` + if (t.size()) + ; + + if (t == TypeRequiresSize{}) + ; + + if (t != TypeRequiresSize{}) + ; +} + +class TypeWithSize { +public: + TypeWithSize(); + bool operator==(const TypeWithSize &other) const; + bool operator!=(const TypeWithSize &other) const; + + unsigned size() const { return 0; } + // Does not have `.empty()` +}; + +void instantiator() { + instantiatedTemplateWithSizeCall(); + instantiatedTemplateWithSizeCall>(); +} diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 32942648378bb..c58bb1af7ae6a 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -2839,6 +2839,16 @@ the configuration (without a prefix: ``Auto``). int a = 5; vs. int a= 5; a += 42; a+= 42; +**SpaceBeforeCaseColon** (``bool``) + If ``false``, spaces will be removed before case colon. + + .. code-block:: c++ + + true: false + switch (x) { vs. switch (x) { + case 1 : break; case 1: break; + } } + **SpaceBeforeCpp11BracedList** (``bool``) If ``true``, a space will be inserted before a C++11 braced list used to initialize an object (after the preceding identifier or type). diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a3038aa03cded..76d4b6bb5acd5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -118,6 +118,10 @@ Modified Compiler Flags `-fno-delete-null-pointer-checks` has gained the power to remove the `nonnull` attribute on `this` for configurations that need it to be nullable. - ``-gsplit-dwarf`` no longer implies ``-g2``. +- ``-fasynchronous-unwind-tables`` is now the default on Linux AArch64/PowerPC. + This behavior matches newer GCC. + (`D91760 `_) + (`D92054 `_) Removed Compiler Flags ------------------------- @@ -289,6 +293,9 @@ clang-format - Option ``IndentPragmas`` has been added to allow #pragma to indented with the current scope level. This is especially useful when using #pragma to mark OpenMP sections of code. +- Option ``SpaceBeforeCaseColon`` has been added to add a space before the + colon in a case or default statement. + libclang -------- diff --git a/clang/docs/tools/dump_format_style.py b/clang/docs/tools/dump_format_style.py index 61167979b3e6b..d01c823a9a20e 100755 --- a/clang/docs/tools/dump_format_style.py +++ b/clang/docs/tools/dump_format_style.py @@ -144,7 +144,7 @@ class State(object): comment += clean_comment_line(line) elif line.startswith('enum'): state = State.InEnum - name = re.sub(r'enum\s+(\w+)\s*\{', '\\1', line) + name = re.sub(r'enum\s+(\w+)\s*(:((\s*\w+)+)\s*)?\{', '\\1', line) enum = Enum(name, comment) elif line.startswith('struct'): state = State.InNestedStruct diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp index 998f175dae546..159b09e4b154d 100644 --- a/clang/examples/Attribute/Attribute.cpp +++ b/clang/examples/Attribute/Attribute.cpp @@ -23,9 +23,10 @@ namespace { struct ExampleAttrInfo : public ParsedAttrInfo { ExampleAttrInfo() { - // Can take an optional string argument (the check that the argument - // actually is a string happens in handleDeclAttribute). - OptArgs = 1; + // Can take up to 15 optional arguments, to emulate accepting a variadic + // number of arguments. This just illustrates how many arguments a + // `ParsedAttrInfo` can hold, we will not use that much in this example. + OptArgs = 15; // GNU-style __attribute__(("example")) and C++-style [[example]] and // [[plugin::example]] supported. static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"}, @@ -39,7 +40,7 @@ struct ExampleAttrInfo : public ParsedAttrInfo { // This attribute appertains to functions only. if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << Attr << "functions"; + << Attr << "functions"; return false; } return true; @@ -55,23 +56,39 @@ struct ExampleAttrInfo : public ParsedAttrInfo { S.Diag(Attr.getLoc(), ID); return AttributeNotApplied; } - // Check if we have an optional string argument. - StringRef Str = ""; + // We make some rules here: + // 1. Only accept at most 3 arguments here. + // 2. The first argument must be a string literal if it exists. + if (Attr.getNumArgs() > 3) { + unsigned ID = S.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, + "'example' attribute only accepts at most three arguments"); + S.Diag(Attr.getLoc(), ID); + return AttributeNotApplied; + } + // If there are arguments, the first argument should be a string literal. if (Attr.getNumArgs() > 0) { - Expr *ArgExpr = Attr.getArgAsExpr(0); + auto *Arg0 = Attr.getArgAsExpr(0); StringLiteral *Literal = - dyn_cast(ArgExpr->IgnoreParenCasts()); - if (Literal) { - Str = Literal->getString(); - } else { - S.Diag(ArgExpr->getExprLoc(), diag::err_attribute_argument_type) - << Attr.getAttrName() << AANT_ArgumentString; + dyn_cast(Arg0->IgnoreParenCasts()); + if (!Literal) { + unsigned ID = S.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, "first argument to the 'example' " + "attribute must be a string literal"); + S.Diag(Attr.getLoc(), ID); return AttributeNotApplied; } + SmallVector ArgsBuf; + for (unsigned i = 0; i < Attr.getNumArgs(); i++) { + ArgsBuf.push_back(Attr.getArgAsExpr(i)); + } + D->addAttr(AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(), + ArgsBuf.size(), Attr.getRange())); + } else { + // Attach an annotate attribute to the Decl. + D->addAttr(AnnotateAttr::Create(S.Context, "example", nullptr, 0, + Attr.getRange())); } - // Attach an annotate attribute to the Decl. - D->addAttr(AnnotateAttr::Create(S.Context, "example(" + Str.str() + ")", - Attr.getRange())); return AttributeApplied; } }; diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 52b14d02a9fff..9ae17692a9faa 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -2823,8 +2823,8 @@ class ASTContext : public RefCountedBase { /// for destruction. template void addDestruction(T *Ptr) const { if (!std::is_trivially_destructible::value) { - auto DestroyPtr = [](void *V) { ((T*)V)->~T(); }; - AddDeallocation(DestroyPtr, (void*)Ptr); + auto DestroyPtr = [](void *V) { static_cast(V)->~T(); }; + AddDeallocation(DestroyPtr, Ptr); } } diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 618fd3f8beb28..8786c02c52c94 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1665,6 +1665,9 @@ class ParmVarDecl : public VarDecl { return ParmVarDeclBits.IsObjCMethodParam; } + /// Determines whether this parameter is destroyed in the callee function. + bool isDestroyedInCallee() const; + unsigned getFunctionScopeDepth() const { if (ParmVarDeclBits.IsObjCMethodParam) return 0; return ParmVarDeclBits.ScopeDepthOrObjCQuals; diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index 8c47047a7526d..ca96b65574bdd 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -255,12 +255,6 @@ inline TypeDependence toTypeDependence(TemplateNameDependence D) { inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { return Dependence(D).type(); } -/// Compute the dependence of a type that depends on the type of an expression, -/// given the dependence of that expression and of its type. -inline TypeDependence typeToTypeDependence(ExprDependence ED, TypeDependence TD) { - return Dependence(ED & ~ExprDependence::Value).type() | - (TD & TypeDependence::VariablyModified); -} inline NestedNameSpecifierDependence toNestedNameSpecifierDependendence(TypeDependence D) { diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 15b81202c11a9..c91f1ca518741 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -578,12 +578,12 @@ class Expr : public ValueStmt { struct EvalStatus { /// Whether the evaluated expression has side effects. /// For example, (f() && 0) can be folded, but it still has side effects. - bool HasSideEffects = false; + bool HasSideEffects; /// Whether the evaluation hit undefined behavior. /// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior. /// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB. - bool HasUndefinedBehavior = false; + bool HasUndefinedBehavior; /// Diag - If this is non-null, it will be filled in with a stack of notes /// indicating why evaluation failed (or why it failed to produce a constant @@ -592,7 +592,10 @@ class Expr : public ValueStmt { /// foldable. If the expression is foldable, but not a constant expression, /// the notes will describes why it isn't a constant expression. If the /// expression *is* a constant expression, no notes will be produced. - SmallVectorImpl *Diag = nullptr; + SmallVectorImpl *Diag; + + EvalStatus() + : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {} // hasSideEffects - Return true if the evaluated expression has // side effects. @@ -603,11 +606,8 @@ class Expr : public ValueStmt { /// EvalResult is a struct with detailed info about an evaluated expression. struct EvalResult : EvalStatus { - /// This is the value the expression can be folded to. + /// Val - This is the value the expression can be folded to. APValue Val; - /// Indicates whether Val contains a pointer or reference or pointer to - /// member naming a templated entity, and thus the value is dependent. - bool Dependent = false; // isGlobalLValue - Return true if the evaluated lvalue expression // is global. diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index dbe75ab9de194..ba0f237a3bc3c 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -72,7 +72,6 @@ class CountPropertyType : PropertyType { def APInt : PropertyType<"llvm::APInt"> { let PassByReference = 1; } def APSInt : PropertyType<"llvm::APSInt"> { let PassByReference = 1; } -def APValue : PropertyType { let PassByReference = 1; } def ArraySizeModifier : EnumPropertyType<"ArrayType::ArraySizeModifier">; def AttrKind : EnumPropertyType<"attr::Kind">; def AutoTypeKeyword : EnumPropertyType; @@ -451,17 +450,6 @@ let Class = PropertyTypeCase in { return TemplateArgument(ctx, value, type); }]>; } -let Class = PropertyTypeCase in { - def : Property<"value", APValue> { - let Read = [{ node.getAsUncommonValue() }]; - } - def : Property<"type", QualType> { - let Read = [{ node.getUncommonValueType() }]; - } - def : Creator<[{ - return TemplateArgument(ctx, type, value); - }]>; -} let Class = PropertyTypeCase in { def : Property<"name", TemplateName> { let Read = [{ node.getAsTemplateOrTemplatePattern() }]; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 61e524793ec70..505ea700fd0e0 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -468,6 +468,8 @@ template class RecursiveASTVisitor { DEF_TRAVERSE_TMPL_INST(Function) #undef DEF_TRAVERSE_TMPL_INST + bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue); + private: // These are helper methods used by more than one Traverse* method. bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); @@ -497,7 +499,6 @@ template class RecursiveASTVisitor { bool VisitOMPClauseWithPreInit(OMPClauseWithPreInit *Node); bool VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *Node); - bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue); bool PostVisitStmt(Stmt *S); }; @@ -767,7 +768,6 @@ bool RecursiveASTVisitor::TraverseTemplateArgument( case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::NullPtr: - case TemplateArgument::UncommonValue: return true; case TemplateArgument::Type: @@ -801,7 +801,6 @@ bool RecursiveASTVisitor::TraverseTemplateArgumentLoc( case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::NullPtr: - case TemplateArgument::UncommonValue: return true; case TemplateArgument::Type: { diff --git a/clang/include/clang/AST/TemplateArgumentVisitor.h b/clang/include/clang/AST/TemplateArgumentVisitor.h index 8c0da70b25eb9..190aa97adf455 100644 --- a/clang/include/clang/AST/TemplateArgumentVisitor.h +++ b/clang/include/clang/AST/TemplateArgumentVisitor.h @@ -37,7 +37,6 @@ class Base { DISPATCH(Declaration); DISPATCH(NullPtr); DISPATCH(Integral); - DISPATCH(UncommonValue); DISPATCH(Template); DISPATCH(TemplateExpansion); DISPATCH(Expression); @@ -60,7 +59,6 @@ class Base { VISIT_METHOD(Declaration); VISIT_METHOD(NullPtr); VISIT_METHOD(Integral); - VISIT_METHOD(UncommonValue); VISIT_METHOD(Template); VISIT_METHOD(TemplateExpansion); VISIT_METHOD(Expression); diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index 9968143e87610..7967f8a91214d 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -51,7 +51,6 @@ template <> struct PointerLikeTypeTraits { namespace clang { -class APValue; class ASTContext; class DiagnosticBuilder; class Expr; @@ -83,12 +82,6 @@ class TemplateArgument { /// that was provided for an integral non-type template parameter. Integral, - /// The template argument is a non-type template argument that can't be - /// represented by the special-case Declaration, NullPtr, or Integral - /// forms. These values are only ever produced by constant evaluation, - /// so cannot be dependent. - UncommonValue, - /// The template argument is a template name that was provided for a /// template template parameter. Template, @@ -132,11 +125,6 @@ class TemplateArgument { }; void *Type; }; - struct V { - unsigned Kind; - const APValue *Value; - void *Type; - }; struct A { unsigned Kind; unsigned NumArgs; @@ -154,7 +142,6 @@ class TemplateArgument { union { struct DA DeclArg; struct I Integer; - struct V Value; struct A Args; struct TA TemplateArg; struct TV TypeOrValue; @@ -170,8 +157,9 @@ class TemplateArgument { TypeOrValue.V = reinterpret_cast(T.getAsOpaquePtr()); } - /// Construct a template argument that refers to a (non-dependent) - /// declaration. + /// Construct a template argument that refers to a + /// declaration, which is either an external declaration or a + /// template declaration. TemplateArgument(ValueDecl *D, QualType QT) { assert(D && "Expected decl"); DeclArg.Kind = Declaration; @@ -181,11 +169,7 @@ class TemplateArgument { /// Construct an integral constant template argument. The memory to /// store the value is allocated with Ctx. - TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value, - QualType Type); - - /// Construct a template argument from an arbitrary constant value. - TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value); + TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type); /// Construct an integral constant template argument with the same /// value as Other but a different type. @@ -268,12 +252,6 @@ class TemplateArgument { /// Whether this template argument is dependent on a template /// parameter such that its result can change from one instantiation to /// another. - /// - /// It's not always meaningful to ask whether a template argument is - /// dependent before it's been converted to match a template parameter; - /// whether a non-type template argument is dependent depends on the - /// corresponding parameter. For an unconverted template argument, this - /// returns true if the argument *might* be dependent. bool isDependent() const; /// Whether this template argument is dependent on a template @@ -356,16 +334,6 @@ class TemplateArgument { Integer.Type = T.getAsOpaquePtr(); } - /// Get the value of an UncommonValue. - const APValue &getAsUncommonValue() const { - return *Value.Value; - } - - /// Get the type of an UncommonValue. - QualType getUncommonValueType() const { - return QualType::getFromOpaquePtr(Value.Type); - } - /// If this is a non-type template argument, get its type. Otherwise, /// returns a null QualType. QualType getNonTypeTemplateArgumentType() const; @@ -510,7 +478,6 @@ class TemplateArgumentLoc { assert(Argument.getKind() == TemplateArgument::NullPtr || Argument.getKind() == TemplateArgument::Integral || Argument.getKind() == TemplateArgument::Declaration || - Argument.getKind() == TemplateArgument::UncommonValue || Argument.getKind() == TemplateArgument::Expression); } @@ -569,11 +536,6 @@ class TemplateArgumentLoc { return LocInfo.getAsExpr(); } - Expr *getSourceUncommonValueExpression() const { - assert(Argument.getKind() == TemplateArgument::UncommonValue); - return LocInfo.getAsExpr(); - } - NestedNameSpecifierLoc getTemplateQualifierLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) @@ -712,6 +674,13 @@ struct alignas(void *) ASTTemplateKWAndArgsInfo { void initializeFrom(SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &List, TemplateArgumentLoc *OutArgArray); + // FIXME: The parameter Deps is the result populated by this method, the + // caller doesn't need it since it is populated by computeDependence. remove + // it. + void initializeFrom(SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo &List, + TemplateArgumentLoc *OutArgArray, + TemplateArgumentDependence &Deps); void initializeFrom(SourceLocation TemplateKWLoc); void copyInto(const TemplateArgumentLoc *ArgArray, diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 1b19a1dfef25e..9db57f64b5921 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -5428,9 +5428,7 @@ class ElaboratedType final ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType, QualType CanonType, TagDecl *OwnedTagDecl) : TypeWithKeyword(Keyword, Elaborated, CanonType, - NamedType->getDependence() | - (NNS ? toTypeDependence(NNS->getDependence()) - : TypeDependence::None)), + NamedType->getDependence()), NNS(NNS), NamedType(NamedType) { ElaboratedTypeBits.HasOwnedTagDecl = false; if (OwnedTagDecl) { diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ca9a8a20a4458..ead6e7952b80c 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1149,7 +1149,6 @@ def SYCLDevice : InheritableAttr { let Subjects = SubjectList<[Function]>; let LangOpts = [SYCLIsDevice]; let Documentation = [SYCLDeviceDocs]; - let PragmaAttributeSupport = 0; } def SYCLKernel : InheritableAttr { @@ -1167,7 +1166,6 @@ def SYCLSimd : InheritableAttr { let Subjects = SubjectList<[Function]>; let LangOpts = [SYCLExplicitSIMD]; let Documentation = [SYCLSimdDocs]; - let PragmaAttributeSupport = 0; } // Available in SYCL explicit SIMD extension. Binds a file scope private @@ -1180,7 +1178,6 @@ def SYCLRegisterNum : InheritableAttr { // for the host device as well let LangOpts = [SYCLExplicitSIMD]; let Documentation = [SYCLRegisterNumDocs]; - let PragmaAttributeSupport = 0; } // Used to mark ESIMD kernel pointer parameters originating from accessors. @@ -1190,7 +1187,6 @@ def SYCLSimdAccessorPtr : InheritableAttr { let Subjects = SubjectList<[ParmVar]>; let LangOpts = [SYCLExplicitSIMD]; let Documentation = [SYCLSimdAccessorPtrDocs]; - let PragmaAttributeSupport = 0; } def SYCLScope : Attr { @@ -1219,7 +1215,6 @@ def SYCLDeviceIndirectlyCallable : InheritableAttr { let Subjects = SubjectList<[Function]>; let LangOpts = [SYCLIsDevice]; let Documentation = [SYCLDeviceIndirectlyCallableDocs]; - let PragmaAttributeSupport = 0; } def SYCLIntelBufferLocation : InheritableAttr { @@ -1244,7 +1239,6 @@ def SYCLIntelKernelArgsRestrict : InheritableAttr { let LangOpts = [ SYCLIsDevice, SYCLIsHost ]; let Documentation = [ SYCLIntelKernelArgsRestrictDocs ]; let SimpleHandler = 1; - let PragmaAttributeSupport = 0; } def SYCLIntelNumSimdWorkItems : InheritableAttr { @@ -1254,7 +1248,6 @@ def SYCLIntelNumSimdWorkItems : InheritableAttr { let LangOpts = [SYCLIsDevice, SYCLIsHost]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [SYCLIntelNumSimdWorkItemsAttrDocs]; - let PragmaAttributeSupport = 0; } def SYCLIntelUseStallEnableClusters : InheritableAttr { @@ -1267,7 +1260,6 @@ def SYCLIntelUseStallEnableClusters : InheritableAttr { } }]; let Documentation = [SYCLIntelUseStallEnableClustersAttrDocs]; - let PragmaAttributeSupport = 0; } def SYCLIntelSchedulerTargetFmaxMhz : InheritableAttr { @@ -1277,7 +1269,6 @@ def SYCLIntelSchedulerTargetFmaxMhz : InheritableAttr { let LangOpts = [SYCLIsDevice, SYCLIsHost]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [SYCLIntelSchedulerTargetFmaxMhzAttrDocs]; - let PragmaAttributeSupport = 0; let AdditionalMembers = [{ static unsigned getMinValue() { return 0; @@ -1286,7 +1277,6 @@ def SYCLIntelSchedulerTargetFmaxMhz : InheritableAttr { return 1024*1024; } }]; - } def SYCLIntelMaxWorkGroupSize : InheritableAttr { @@ -1297,11 +1287,19 @@ def SYCLIntelMaxWorkGroupSize : InheritableAttr { ExprArgument<"ZDim">]; let LangOpts = [SYCLIsDevice, SYCLIsHost]; let Subjects = SubjectList<[Function], ErrorDiag>; - let PragmaAttributeSupport = 0; let AdditionalMembers = [{ ArrayRef dimensions() const { return {getXDim(), getYDim(), getZDim()}; } + Optional getXDimVal(ASTContext &Ctx) const { + return getXDim()->getIntegerConstantExpr(Ctx); + } + Optional getYDimVal(ASTContext &Ctx) const { + return getYDim()->getIntegerConstantExpr(Ctx); + } + Optional getZDimVal(ASTContext &Ctx) const { + return getZDim()->getIntegerConstantExpr(Ctx); + } }]; let Documentation = [SYCLIntelMaxWorkGroupSizeAttrDocs]; } @@ -1313,7 +1311,6 @@ def SYCLIntelMaxGlobalWorkDim : InheritableAttr { let LangOpts = [SYCLIsDevice, SYCLIsHost]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [SYCLIntelMaxGlobalWorkDimAttrDocs]; - let PragmaAttributeSupport = 0; } def SYCLIntelNoGlobalWorkOffset : InheritableAttr { @@ -1323,7 +1320,6 @@ def SYCLIntelNoGlobalWorkOffset : InheritableAttr { let LangOpts = [SYCLIsDevice, SYCLIsHost]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [SYCLIntelNoGlobalWorkOffsetAttrDocs]; - let PragmaAttributeSupport = 0; } def SYCLIntelLoopFuse : InheritableAttr { @@ -1404,7 +1400,6 @@ def IntelReqdSubGroupSize: InheritableAttr { let Subjects = SubjectList<[Function, CXXMethod], ErrorDiag>; let Documentation = [IntelReqdSubGroupSizeDocs]; let LangOpts = [OpenCL, SYCLIsDevice, SYCLIsHost]; - let PragmaAttributeSupport = 0; } // This attribute is both a type attribute, and a declaration attribute (for @@ -2124,7 +2119,6 @@ def SYCLIntelPipeIO : Attr { let LangOpts = [SYCLIsDevice, SYCLIsHost]; let Subjects = SubjectList<[Var]>; let Documentation = [SYCLIntelPipeIOAttrDocs]; - let PragmaAttributeSupport = 0; } // Variadic integral arguments. @@ -2853,6 +2847,15 @@ def ReqdWorkGroupSize : InheritableAttr { ArrayRef dimensions() const { return {getXDim(), getYDim(), getZDim()}; } + Optional getXDimVal(ASTContext &Ctx) const { + return getXDim()->getIntegerConstantExpr(Ctx); + } + Optional getYDimVal(ASTContext &Ctx) const { + return getYDim()->getIntegerConstantExpr(Ctx); + } + Optional getZDimVal(ASTContext &Ctx) const { + return getZDim()->getIntegerConstantExpr(Ctx); + } }]; let Documentation = [ReqdWorkGroupSizeAttrDocs]; } diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index ef4fa31256cd4..5c540812ed312 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -30,8 +30,6 @@ namespace clang { /// Bitfields of CodeGenOptions, split out from CodeGenOptions to ensure /// that this large collection of bitfields is a trivial class type. class CodeGenOptionsBase { - friend class CompilerInvocation; - public: #define CODEGENOPT(Name, Bits, Default) unsigned Name : Bits; #define ENUM_CODEGENOPT(Name, Type, Bits, Default) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 61cdf13154818..2a3acc3efdfd0 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -89,6 +89,8 @@ def err_drv_invalid_thread_model_for_target : Error< "invalid thread model '%0' in '%1' for this target">; def err_drv_invalid_linker_name : Error< "invalid linker name in argument '%0'">; +def err_drv_invalid_pgo_instrumentor : Error< + "invalid PGO instrumentor in argument '%0'">; def err_drv_invalid_rtlib_name : Error< "invalid runtime library name in argument '%0'">; def err_drv_unsupported_rtlib_for_platform : Error< diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index b9f8c78e43da8..def189f659947 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -108,6 +108,8 @@ def err_fe_action_not_available : Error< "action %0 not compiled in">; def err_fe_invalid_alignment : Error< "invalid value '%1' in '%0'; alignment must be a power of 2">; +def err_fe_invalid_wchar_type + : Error<"invalid wchar_t type '%0'; must be one of 'char', 'short', 'int'">; def err_fe_invalid_exception_model : Error<"invalid exception model '%select{none|dwarf|sjlj|arm|seh|wasm|aix}0' for target '%1'">; def warn_fe_concepts_ts_flag : Warning< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index eafded7e4455e..9847824cfb291 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4695,6 +4695,8 @@ def err_non_type_template_arg_subobject : Error< "non-type template argument refers to subobject '%0'">; def err_non_type_template_arg_addr_label_diff : Error< "template argument / label address difference / what did you expect?">; +def err_non_type_template_arg_unsupported : Error< + "sorry, non-type template argument of type %0 is not yet supported">; def err_template_arg_not_convertible : Error< "non-type template argument of type %0 cannot be converted to a value " "of type %1">; @@ -4746,6 +4748,9 @@ def err_template_arg_not_object_or_func : Error< "non-type template argument does not refer to an object or function">; def err_template_arg_not_pointer_to_member_form : Error< "non-type template argument is not a pointer to member constant">; +def err_template_arg_member_ptr_base_derived_not_supported : Error< + "sorry, non-type template argument of pointer-to-member type %1 that refers " + "to member %q0 of a different class is not supported yet">; def ext_template_arg_extra_parens : ExtWarn< "address non-type template argument cannot be surrounded by parentheses">; def warn_cxx98_compat_template_arg_extra_parens : Warning< diff --git a/clang/include/clang/Basic/FileEntry.h b/clang/include/clang/Basic/FileEntry.h index aa7bedec44ac1..6e91b42e18b71 100644 --- a/clang/include/clang/Basic/FileEntry.h +++ b/clang/include/clang/Basic/FileEntry.h @@ -25,6 +25,9 @@ #include "llvm/Support/FileSystem/UniqueID.h" namespace llvm { + +class MemoryBuffer; + namespace vfs { class File; @@ -67,6 +70,7 @@ class FileEntryRef { inline unsigned getUID() const; inline const llvm::sys::fs::UniqueID &getUniqueID() const; inline time_t getModificationTime() const; + inline bool isNamedPipe() const; inline void closeFile() const; /// Check if the underlying FileEntry is the same, intentially ignoring @@ -339,6 +343,9 @@ class FileEntry { /// The open file, if it is owned by the \p FileEntry. mutable std::unique_ptr File; + /// The file content, if it is owned by the \p FileEntry. + std::unique_ptr Content; + // First access name for this FileEntry. // // This is Optional only to allow delayed construction (FileEntryRef has no @@ -390,6 +397,8 @@ time_t FileEntryRef::getModificationTime() const { return getFileEntry().getModificationTime(); } +bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); } + void FileEntryRef::closeFile() const { getFileEntry().closeFile(); } } // end namespace clang diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index 449aec2b3541e..974771a8f8f39 100644 --- a/clang/include/clang/Basic/FileManager.h +++ b/clang/include/clang/Basic/FileManager.h @@ -99,6 +99,9 @@ class FileManager : public RefCountedBase { std::unique_ptr>> SeenBypassFileEntries; + /// The file entry for stdin, if it has been accessed through the FileManager. + Optional STDIN; + /// The canonical names of files and directories . llvm::DenseMap CanonicalNames; @@ -217,6 +220,14 @@ class FileManager : public RefCountedBase { bool OpenFile = false, bool CacheFailure = true); + /// Get the FileEntryRef for stdin, returning an error if stdin cannot be + /// read. + /// + /// This reads and caches stdin before returning. Subsequent calls return the + /// same file entry, and a reference to the cached input is returned by calls + /// to getBufferForFile. + llvm::Expected getSTDIN(); + /// Get a FileEntryRef if it exists, without doing anything on error. llvm::Optional getOptionalFileRef(StringRef Filename, bool OpenFile = false, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4187eba05d459..1d22e07246e9b 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -698,7 +698,7 @@ def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias, AliasArgs<["1"]>; def Ofast : Joined<["-"], "Ofast">, Group, Flags<[CC1Option]>; def P : Flag<["-"], "P">, Flags<[CC1Option]>, Group, HelpText<"Disable linemarker output in -E mode">, - MarshallingInfoNegativeFlag<"PreprocessorOutputOpts.ShowLineMarkers">; + MarshallingInfoFlag<"PreprocessorOutputOpts.ShowLineMarkers", "true">, IsNegative; def Qy : Flag<["-"], "Qy">, Flags<[CC1Option]>, HelpText<"Emit metadata containing compiler name and version">; def Qn : Flag<["-"], "Qn">, Flags<[CC1Option]>, @@ -930,10 +930,8 @@ def fcuda_flush_denormals_to_zero : Flag<["-"], "fcuda-flush-denormals-to-zero"> def fno_cuda_flush_denormals_to_zero : Flag<["-"], "fno-cuda-flush-denormals-to-zero">; defm cuda_approx_transcendentals : OptInFFlag<"cuda-approx-transcendentals", "Use", "Don't use", " approximate transcendental functions">; -defm gpu_rdc : BoolFOption<"gpu-rdc", - "LangOpts->GPURelocatableDeviceCode", DefaultsToFalse, - ChangedBy, - ResetBy>; +defm gpu_rdc : OptInFFlag<"gpu-rdc", + "Generate relocatable device code, also known as separate compilation mode", "", "">; def : Flag<["-"], "fcuda-rdc">, Alias; def : Flag<["-"], "fno-cuda-rdc">, Alias; defm cuda_short_ptr : OptInFFlag<"cuda-short-ptr", @@ -950,21 +948,16 @@ def hip_version_EQ : Joined<["--"], "hip-version=">, HelpText<"HIP version in the format of major.minor.patch">; def fhip_dump_offload_linker_script : Flag<["-"], "fhip-dump-offload-linker-script">, Group, Flags<[NoArgumentUnused, HelpHidden]>; -defm hip_new_launch_api : BoolFOption<"hip-new-launch-api", - "LangOpts->HIPUseNewLaunchAPI", DefaultsToFalse, - ChangedBy, ResetBy, - BothFlags<[], " new kernel launching API for HIP">>; +defm hip_new_launch_api : OptInFFlag<"hip-new-launch-api", + "Use", "Don't use", " new kernel launching API for HIP">; defm gpu_allow_device_init : OptInFFlag<"gpu-allow-device-init", "Allow", "Don't allow", " device side init function in HIP">; -defm gpu_defer_diag : BoolFOption<"gpu-defer-diag", - "LangOpts->GPUDeferDiag", DefaultsToFalse, - ChangedBy, ResetBy, - BothFlags<[], " host/device related diagnostic messages for CUDA/HIP">>; -defm gpu_exclude_wrong_side_overloads : BoolFOption<"gpu-exclude-wrong-side-overloads", - "LangOpts->GPUExcludeWrongSideOverloads", DefaultsToFalse, - ChangedBy, - ResetBy, - BothFlags<[HelpHidden], " in overloading resolution for CUDA/HIP">>; +defm gpu_defer_diag : OptInFFlag<"gpu-defer-diag", + "Defer", "Don't defer", " host/device related diagnostic messages" + " for CUDA/HIP">; +defm gpu_exclude_wrong_side_overloads : OptInFFlag<"gpu-exclude-wrong-side-overloads", + "Always exclude wrong side overloads", "Exclude wrong side overloads only if there are same side overloads", + " in overloading resolution for CUDA/HIP", [HelpHidden]>; def gpu_max_threads_per_block_EQ : Joined<["--"], "gpu-max-threads-per-block=">, Flags<[CC1Option]>, HelpText<"Default max threads per block for kernel launch bounds for HIP">; @@ -1016,31 +1009,21 @@ def interface_stub_version_EQ : JoinedOrSeparate<["-"], "interface-stub-version= def exported__symbols__list : Separate<["-"], "exported_symbols_list">; def e : JoinedOrSeparate<["-"], "e">, Flags<[LinkerInput]>, Group; def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group, Flags<[CC1Option]>, - HelpText<"Max total number of preprocessed tokens for -Wmax-tokens.">, - MarshallingInfoStringInt<"LangOpts->MaxTokens">; + HelpText<"Max total number of preprocessed tokens for -Wmax-tokens.">; def fPIC : Flag<["-"], "fPIC">, Group; def fno_PIC : Flag<["-"], "fno-PIC">, Group; def fPIE : Flag<["-"], "fPIE">, Group; def fno_PIE : Flag<["-"], "fno-PIE">, Group; -defm access_control : BoolFOption<"access-control", - "LangOpts->AccessControl", DefaultsToTrue, - ChangedBy, - ResetBy>; +defm access_control : OptOutFFlag<"access-control", "", "Disable C++ access control">; def falign_functions : Flag<["-"], "falign-functions">, Group; def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group; def fno_align_functions: Flag<["-"], "fno-align-functions">, Group; -defm allow_editor_placeholders : BoolFOption<"allow-editor-placeholders", - "LangOpts->AllowEditorPlaceholders", DefaultsToFalse, - ChangedBy, - ResetBy>; +defm allow_editor_placeholders : OptInFFlag<"allow-editor-placeholders", "Treat editor placeholders as valid source code">; def fallow_unsupported : Flag<["-"], "fallow-unsupported">, Group; def fapple_kext : Flag<["-"], "fapple-kext">, Group, Flags<[CC1Option]>, - HelpText<"Use Apple's kernel extensions ABI">, - MarshallingInfoFlag<"LangOpts->AppleKext">; -defm apple_pragma_pack : BoolFOption<"apple-pragma-pack", - "LangOpts->ApplePragmaPack", DefaultsToFalse, - ChangedBy, - ResetBy>; + HelpText<"Use Apple's kernel extensions ABI">; +def fapple_pragma_pack : Flag<["-"], "fapple-pragma-pack">, Group, Flags<[CC1Option]>, + HelpText<"Enable Apple gcc-compatible #pragma pack handling">; def shared_libsan : Flag<["-"], "shared-libsan">, HelpText<"Dynamically link the sanitizer runtime">; def static_libsan : Flag<["-"], "static-libsan">, @@ -1073,19 +1056,14 @@ defm coroutines_ts : OptInFFlag<"coroutines-ts", "Enable support for the C++ Cor def fembed_bitcode_EQ : Joined<["-"], "fembed-bitcode=">, Group, Flags<[NoXarchOption, CC1Option, CC1AsOption]>, MetaVarName<"