diff --git a/.arclint b/.arclint index 246ff9f39d475..27d838eb153f2 100644 --- a/.arclint +++ b/.arclint @@ -6,6 +6,9 @@ "script-and-regex.regex": "/^(?P[[:alpha:]]+)\n(?P[^\n]+)\n(====|(?P\\d),(?P\\d)\n(?P.*)>>>>\n(?P.*)<<<<\n)$/s", "include": [ "(\\.(cc|cpp|h)$)" + ], + "exclude": [ + "(^clang/test/)" ] } } diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp index 7d540d83037b6..70d4d7cfdff34 100644 --- a/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/FindAllSymbols.cpp @@ -99,7 +99,7 @@ CreateSymbolInfo(const NamedDecl *ND, const SourceManager &SM, SourceLocation Loc = SM.getExpansionLoc(ND->getLocation()); if (!Loc.isValid()) { - llvm::errs() << "Declaration " << ND->getNameAsString() << "(" + llvm::errs() << "Declaration " << ND->getDeclName() << "(" << ND->getDeclKindName() << ") has invalid declaration location."; return llvm::None; diff --git a/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp b/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp index 271bd3d6ef200..a9b773353fe69 100644 --- a/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp +++ b/clang-tools-extra/clang-move/HelperDeclRefGraph.cpp @@ -116,7 +116,7 @@ void HelperDeclRGBuilder::run( const auto *DC = Result.Nodes.getNodeAs("dc"); assert(DC); LLVM_DEBUG(llvm::dbgs() << "Find helper function usage: " - << FuncRef->getDecl()->getNameAsString() << " (" + << FuncRef->getDecl()->getDeclName() << " (" << FuncRef->getDecl() << ")\n"); RG->addEdge( getOutmostClassOrFunDecl(DC->getCanonicalDecl()), @@ -126,7 +126,7 @@ void HelperDeclRGBuilder::run( const auto *DC = Result.Nodes.getNodeAs("dc"); assert(DC); LLVM_DEBUG(llvm::dbgs() - << "Find helper class usage: " << UsedClass->getNameAsString() + << "Find helper class usage: " << UsedClass->getDeclName() << " (" << UsedClass << ")\n"); RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass); } diff --git a/clang-tools-extra/clang-move/Move.cpp b/clang-tools-extra/clang-move/Move.cpp index 3f09f68a8046f..24f819ca4ca29 100644 --- a/clang-tools-extra/clang-move/Move.cpp +++ b/clang-tools-extra/clang-move/Move.cpp @@ -675,8 +675,8 @@ void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) { Result.Nodes.getNodeAs("helper_decls")) { MovedDecls.push_back(ND); HelperDeclarations.push_back(ND); - LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " (" - << ND << ")\n"); + LLVM_DEBUG(llvm::dbgs() + << "Add helper : " << ND->getDeclName() << " (" << ND << ")\n"); } else if (const auto *UD = Result.Nodes.getNodeAs("using_decl")) { MovedDecls.push_back(UD); } @@ -735,12 +735,12 @@ void ClangMoveTool::removeDeclsInOldFiles() { // We remove the helper declarations which are not used in the old.cc after // moving the given declarations. for (const auto *D : HelperDeclarations) { - LLVM_DEBUG(llvm::dbgs() << "Check helper is used: " - << D->getNameAsString() << " (" << D << ")\n"); + LLVM_DEBUG(llvm::dbgs() << "Check helper is used: " << D->getDeclName() + << " (" << D << ")\n"); if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl( D->getCanonicalDecl()))) { LLVM_DEBUG(llvm::dbgs() << "Helper removed in old.cc: " - << D->getNameAsString() << " (" << D << ")\n"); + << D->getDeclName() << " (" << D << ")\n"); RemovedDecls.push_back(D); } } @@ -820,7 +820,7 @@ void ClangMoveTool::moveDeclsToNewFiles() { D->getCanonicalDecl()))) continue; - LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString() + LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getDeclName() << " " << D << "\n"); ActualNewCCDecls.push_back(D); } diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp index 737d85e092d97..c99931e0aa3a2 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp @@ -10,6 +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/raw_ostream.h" namespace clang { @@ -126,7 +127,7 @@ bool ClangTidyCheck::OptionsView::get(StringRef LocalName, llvm::Expected ValueOr = get(LocalName); if (ValueOr) return *ValueOr; - logErrToStdErr(ValueOr.takeError()); + logIfOptionParsingError(ValueOr.takeError()); return Default; } @@ -145,7 +146,7 @@ bool ClangTidyCheck::OptionsView::getLocalOrGlobal(StringRef LocalName, llvm::Expected ValueOr = getLocalOrGlobal(LocalName); if (ValueOr) return *ValueOr; - logErrToStdErr(ValueOr.takeError()); + logIfOptionParsingError(ValueOr.takeError()); return Default; } @@ -204,13 +205,33 @@ llvm::Expected ClangTidyCheck::OptionsView::getEnumInt( Iter->getValue().Value); } -void ClangTidyCheck::OptionsView::logErrToStdErr(llvm::Error &&Err) { - llvm::logAllUnhandledErrors( - llvm::handleErrors(std::move(Err), - [](const MissingOptionError &) -> llvm::Error { - return llvm::Error::success(); - }), - llvm::errs(), "warning: "); +void ClangTidyCheck::OptionsView::logIfOptionParsingError(llvm::Error &&Err) { + if (auto RemainingErrors = + llvm::handleErrors(std::move(Err), [](const MissingOptionError &) {})) + llvm::logAllUnhandledErrors(std::move(RemainingErrors), + llvm::WithColor::warning()); } + +template <> +Optional ClangTidyCheck::OptionsView::getOptional( + StringRef LocalName) const { + if (auto ValueOr = get(LocalName)) + return *ValueOr; + else + consumeError(ValueOr.takeError()); + return llvm::None; +} + +template <> +Optional +ClangTidyCheck::OptionsView::getOptionalLocalOrGlobal( + StringRef LocalName) const { + if (auto ValueOr = getLocalOrGlobal(LocalName)) + return *ValueOr; + else + consumeError(ValueOr.takeError()); + return llvm::None; +} + } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.h b/clang-tools-extra/clang-tidy/ClangTidyCheck.h index 4df8071c841e0..6237e216656be 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyCheck.h +++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.h @@ -268,7 +268,7 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { if (llvm::Expected ValueOr = get(LocalName)) return *ValueOr; else - logErrToStdErr(ValueOr.takeError()); + logIfOptionParsingError(ValueOr.takeError()); return Default; } @@ -314,7 +314,7 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { if (llvm::Expected ValueOr = getLocalOrGlobal(LocalName)) return *ValueOr; else - logErrToStdErr(ValueOr.takeError()); + logIfOptionParsingError(ValueOr.takeError()); return Default; } @@ -353,7 +353,7 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { if (auto ValueOr = get(LocalName, IgnoreCase)) return *ValueOr; else - logErrToStdErr(ValueOr.takeError()); + logIfOptionParsingError(ValueOr.takeError()); return Default; } @@ -395,10 +395,35 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { if (auto ValueOr = getLocalOrGlobal(LocalName, IgnoreCase)) return *ValueOr; else - logErrToStdErr(ValueOr.takeError()); + logIfOptionParsingError(ValueOr.takeError()); return Default; } + /// Returns the value for the option \p LocalName represented as a ``T``. + /// If the option is missing returns None, if the option can't be parsed + /// as a ``T``, log that to stderr and return None. + template + llvm::Optional getOptional(StringRef LocalName) const { + if (auto ValueOr = get(LocalName)) + return *ValueOr; + else + logIfOptionParsingError(ValueOr.takeError()); + return llvm::None; + } + + /// Returns the value for the local or global option \p LocalName + /// represented as a ``T``. + /// If the option is missing returns None, if the + /// option can't be parsed as a ``T``, log that to stderr and return None. + template + llvm::Optional getOptionalLocalOrGlobal(StringRef LocalName) const { + if (auto ValueOr = getLocalOrGlobal(LocalName)) + return *ValueOr; + else + logIfOptionParsingError(ValueOr.takeError()); + return llvm::None; + } + /// Stores an option with the check-local name \p LocalName with /// string value \p Value to \p Options. void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, @@ -456,7 +481,8 @@ class ClangTidyCheck : public ast_matchers::MatchFinder::MatchCallback { void storeInt(ClangTidyOptions::OptionMap &Options, StringRef LocalName, int64_t Value) const; - static void logErrToStdErr(llvm::Error &&Err); + /// Logs an Error to stderr if a \p Err is not a MissingOptionError. + static void logIfOptionParsingError(llvm::Error &&Err); std::string NamePrefix; const ClangTidyOptions::OptionMap &CheckOptions; @@ -524,6 +550,19 @@ void ClangTidyCheck::OptionsView::store( ClangTidyOptions::OptionMap &Options, StringRef LocalName, bool Value) const; +/// Returns the value for the option \p LocalName. +/// If the option is missing returns None. +template <> +Optional ClangTidyCheck::OptionsView::getOptional( + StringRef LocalName) const; + +/// Returns the value for the local or global option \p LocalName. +/// If the option is missing returns None. +template <> +Optional +ClangTidyCheck::OptionsView::getOptionalLocalOrGlobal( + StringRef LocalName) const; + } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index 19ba47f005dc8..6b28cb2bdd13d 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -70,7 +70,7 @@ struct NOptionMap { NOptionMap(IO &, const ClangTidyOptions::OptionMap &OptionMap) { Options.reserve(OptionMap.size()); for (const auto &KeyValue : OptionMap) - Options.emplace_back(KeyValue.getKey(), KeyValue.getValue().Value); + Options.emplace_back(std::string(KeyValue.getKey()), KeyValue.getValue().Value); } ClangTidyOptions::OptionMap denormalize(IO &) { ClangTidyOptions::OptionMap Map; diff --git a/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp index 3591a7da8eb77..0720c7e689a18 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BadSignalToKillThreadCheck.cpp @@ -30,7 +30,8 @@ static Preprocessor *PP; void BadSignalToKillThreadCheck::check(const MatchFinder::MatchResult &Result) { const auto IsSigterm = [](const auto &KeyValue) -> bool { - return KeyValue.first->getName() == "SIGTERM"; + return KeyValue.first->getName() == "SIGTERM" && + KeyValue.first->hasMacroDefinition(); }; const auto TryExpandAsInteger = [](Preprocessor::macro_iterator It) -> Optional { @@ -38,6 +39,8 @@ void BadSignalToKillThreadCheck::check(const MatchFinder::MatchResult &Result) { return llvm::None; const MacroInfo *MI = PP->getMacroInfo(It->first); const Token &T = MI->tokens().back(); + if (!T.isLiteral()) + return llvm::None; StringRef ValueStr = StringRef(T.getLiteralData(), T.getLength()); llvm::APInt IntValue; diff --git a/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp index b764bdbf7c4c5..17dab1b0f73e3 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp @@ -20,53 +20,68 @@ void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( traverse( ast_type_traits::TK_AsIs, - ifStmt(hasCondition(findAll(implicitCastExpr( - unless(hasParent(unaryOperator(hasOperatorName("!")))), - hasSourceExpression(expr( - hasType(pointerType(pointee(booleanType()))), - ignoringParenImpCasts(declRefExpr().bind("expr")))), - hasCastKind(CK_PointerToBoolean)))), - unless(isInTemplateInstantiation())) + ifStmt( + hasCondition(findAll(implicitCastExpr( + unless(hasParent(unaryOperator(hasOperatorName("!")))), + hasSourceExpression(expr( + hasType(pointerType(pointee(booleanType()))), + ignoringParenImpCasts(anyOf(declRefExpr().bind("expr"), + memberExpr().bind("expr"))))), + hasCastKind(CK_PointerToBoolean)))), + unless(isInTemplateInstantiation())) .bind("if")), this); } -void BoolPointerImplicitConversionCheck::check( - const MatchFinder::MatchResult &Result) { - auto *If = Result.Nodes.getNodeAs("if"); - auto *Var = Result.Nodes.getNodeAs("expr"); - +static void checkImpl(const MatchFinder::MatchResult &Result, const Expr *Ref, + const IfStmt *If, + const ast_matchers::internal::Matcher &RefMatcher, + ClangTidyCheck &Check) { // Ignore macros. - if (Var->getBeginLoc().isMacroID()) + if (Ref->getBeginLoc().isMacroID()) return; - // Only allow variable accesses for now, no function calls or member exprs. + // Only allow variable accesses and member exprs for now, no function calls. // Check that we don't dereference the variable anywhere within the if. This // avoids false positives for checks of the pointer for nullptr before it is // dereferenced. If there is a dereferencing operator on this variable don't // emit a diagnostic. Also ignore array subscripts. - const Decl *D = Var->getDecl(); - auto DeclRef = ignoringParenImpCasts(declRefExpr(to(equalsNode(D)))); - if (!match(findAll( - unaryOperator(hasOperatorName("*"), hasUnaryOperand(DeclRef))), + if (!match(findAll(unaryOperator(hasOperatorName("*"), + hasUnaryOperand(RefMatcher))), *If, *Result.Context) .empty() || - !match(findAll(arraySubscriptExpr(hasBase(DeclRef))), *If, + !match(findAll(arraySubscriptExpr(hasBase(RefMatcher))), *If, *Result.Context) .empty() || // FIXME: We should still warn if the paremater is implicitly converted to // bool. - !match(findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(DeclRef)))), - *If, *Result.Context) + !match( + findAll(callExpr(hasAnyArgument(ignoringParenImpCasts(RefMatcher)))), + *If, *Result.Context) .empty() || - !match(findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(DeclRef))))), - *If, *Result.Context) + !match( + findAll(cxxDeleteExpr(has(ignoringParenImpCasts(expr(RefMatcher))))), + *If, *Result.Context) .empty()) return; - diag(Var->getBeginLoc(), "dubious check of 'bool *' against 'nullptr', did " - "you mean to dereference it?") - << FixItHint::CreateInsertion(Var->getBeginLoc(), "*"); + Check.diag(Ref->getBeginLoc(), + "dubious check of 'bool *' against 'nullptr', did " + "you mean to dereference it?") + << FixItHint::CreateInsertion(Ref->getBeginLoc(), "*"); +} + +void BoolPointerImplicitConversionCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *If = Result.Nodes.getNodeAs("if"); + if (const auto *E = Result.Nodes.getNodeAs("expr")) { + const Decl *D = isa(E) ? cast(E)->getDecl() + : cast(E)->getMemberDecl(); + const auto M = + ignoringParenImpCasts(anyOf(declRefExpr(to(equalsNode(D))), + memberExpr(hasDeclaration(equalsNode(D))))); + checkImpl(Result, E, If, M, *this); + } } } // namespace bugprone diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index c885aac89072a..c2a32474b2a8b 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -8,6 +8,7 @@ #include "IdentifierNamingCheck.h" +#include "../GlobList.h" #include "clang/AST/CXXInheritance.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" @@ -15,7 +16,8 @@ #include "llvm/ADT/DenseMapInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Error.h" -#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Regex.h" #define DEBUG_TYPE "clang-tidy" @@ -119,54 +121,59 @@ static StringRef const StyleNames[] = { #undef NAMING_KEYS // clang-format on +static std::vector> +getNamingStyles(const ClangTidyCheck::OptionsView &Options) { + std::vector> Styles; + Styles.reserve(array_lengthof(StyleNames)); + for (auto const &StyleName : StyleNames) { + auto CaseOptional = Options.getOptional( + (StyleName + "Case").str()); + auto Prefix = Options.get((StyleName + "Prefix").str(), ""); + auto Postfix = Options.get((StyleName + "Suffix").str(), ""); + + if (CaseOptional || !Prefix.empty() || !Postfix.empty()) + Styles.emplace_back(IdentifierNamingCheck::NamingStyle{ + std::move(CaseOptional), std::move(Prefix), std::move(Postfix)}); + else + Styles.emplace_back(llvm::None); + } + return Styles; +} + IdentifierNamingCheck::IdentifierNamingCheck(StringRef Name, ClangTidyContext *Context) - : RenamerClangTidyCheck(Name, Context), + : RenamerClangTidyCheck(Name, Context), Context(Context), CheckName(Name), + GetConfigPerFile(Options.get("GetConfigPerFile", true)), IgnoreFailedSplit(Options.get("IgnoreFailedSplit", false)), IgnoreMainLikeFunctions(Options.get("IgnoreMainLikeFunctions", false)) { - for (auto const &Name : StyleNames) { - auto CaseOptional = [&]() -> llvm::Optional { - auto ValueOr = Options.get((Name + "Case").str()); - if (ValueOr) - return *ValueOr; - llvm::logAllUnhandledErrors( - llvm::handleErrors(ValueOr.takeError(), - [](const MissingOptionError &) -> llvm::Error { - return llvm::Error::success(); - }), - llvm::errs(), "warning: "); - return llvm::None; - }(); - - auto prefix = Options.get((Name + "Prefix").str(), ""); - auto postfix = Options.get((Name + "Suffix").str(), ""); - - if (CaseOptional || !prefix.empty() || !postfix.empty()) { - NamingStyles.push_back(NamingStyle(CaseOptional, prefix, postfix)); - } else { - NamingStyles.push_back(llvm::None); - } - } + auto IterAndInserted = NamingStylesCache.try_emplace( + llvm::sys::path::parent_path(Context->getCurrentFile()), + getNamingStyles(Options)); + assert(IterAndInserted.second && "Couldn't insert Style"); + // Holding a reference to the data in the vector is safe as it should never + // move. + MainFileStyle = IterAndInserted.first->getValue(); } IdentifierNamingCheck::~IdentifierNamingCheck() = default; void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { RenamerClangTidyCheck::storeOptions(Opts); - for (size_t i = 0; i < SK_Count; ++i) { - if (NamingStyles[i]) { - if (NamingStyles[i]->Case) { - Options.store(Opts, (StyleNames[i] + "Case").str(), - *NamingStyles[i]->Case); - } - Options.store(Opts, (StyleNames[i] + "Prefix").str(), - NamingStyles[i]->Prefix); - Options.store(Opts, (StyleNames[i] + "Suffix").str(), - NamingStyles[i]->Suffix); - } + ArrayRef> NamingStyles = + getStyleForFile(Context->getCurrentFile()); + for (size_t I = 0; I < SK_Count; ++I) { + if (!NamingStyles[I]) + continue; + if (NamingStyles[I]->Case) + Options.store(Opts, (StyleNames[I] + "Case").str(), + *NamingStyles[I]->Case); + Options.store(Opts, (StyleNames[I] + "Prefix").str(), + NamingStyles[I]->Prefix); + Options.store(Opts, (StyleNames[I] + "Suffix").str(), + NamingStyles[I]->Suffix); } - + Options.store(Opts, "GetConfigPerFile", GetConfigPerFile); Options.store(Opts, "IgnoreFailedSplit", IgnoreFailedSplit); Options.store(Opts, "IgnoreMainLikeFunctions", IgnoreMainLikeFunctions); } @@ -183,14 +190,9 @@ static bool matchesStyle(StringRef Name, llvm::Regex("^[a-z]([a-z0-9]*(_[A-Z])?)*"), }; - if (Name.startswith(Style.Prefix)) - Name = Name.drop_front(Style.Prefix.size()); - else + if (!Name.consume_front(Style.Prefix)) return false; - - if (Name.endswith(Style.Suffix)) - Name = Name.drop_back(Style.Suffix.size()); - else + if (!Name.consume_back(Style.Suffix)) return false; // Ensure the name doesn't have any extra underscores beyond those specified @@ -213,9 +215,10 @@ static std::string fixupWithCase(StringRef Name, Name.split(Substrs, "_", -1, false); SmallVector Words; + SmallVector Groups; for (auto Substr : Substrs) { while (!Substr.empty()) { - SmallVector Groups; + Groups.clear(); if (!Splitter.match(Substr, &Groups)) break; @@ -233,12 +236,12 @@ static std::string fixupWithCase(StringRef Name, } if (Words.empty()) - return std::string(Name); + return Name.str(); - std::string Fixup; + SmallString<128> Fixup; switch (Case) { case IdentifierNamingCheck::CT_AnyCase: - Fixup += Name; + return Name.str(); break; case IdentifierNamingCheck::CT_LowerCase: @@ -259,7 +262,7 @@ static std::string fixupWithCase(StringRef Name, case IdentifierNamingCheck::CT_CamelCase: for (auto const &Word : Words) { - Fixup += Word.substr(0, 1).upper(); + Fixup += toupper(Word.front()); Fixup += Word.substr(1).lower(); } break; @@ -269,7 +272,7 @@ static std::string fixupWithCase(StringRef Name, if (&Word == &Words.front()) { Fixup += Word.lower(); } else { - Fixup += Word.substr(0, 1).upper(); + Fixup += toupper(Word.front()); Fixup += Word.substr(1).lower(); } } @@ -279,7 +282,7 @@ static std::string fixupWithCase(StringRef Name, for (auto const &Word : Words) { if (&Word != &Words.front()) Fixup += "_"; - Fixup += Word.substr(0, 1).upper(); + Fixup += toupper(Word.front()); Fixup += Word.substr(1).lower(); } break; @@ -288,16 +291,16 @@ static std::string fixupWithCase(StringRef Name, for (auto const &Word : Words) { if (&Word != &Words.front()) { Fixup += "_"; - Fixup += Word.substr(0, 1).upper(); + Fixup += toupper(Word.front()); } else { - Fixup += Word.substr(0, 1).lower(); + Fixup += tolower(Word.front()); } Fixup += Word.substr(1).lower(); } break; } - return Fixup; + return Fixup.str().str(); } static bool isParamInMainLikeFunction(const ParmVarDecl &ParmDecl, @@ -374,8 +377,7 @@ fixupWithStyle(StringRef Name, static StyleKind findStyleKind( const NamedDecl *D, - const std::vector> - &NamingStyles, + ArrayRef> NamingStyles, bool IgnoreMainLikeFunctions) { assert(D && D->getIdentifier() && !D->getName().empty() && !D->isImplicit() && "Decl must be an explicit identifier with a name."); @@ -652,74 +654,82 @@ static StyleKind findStyleKind( return SK_Invalid; } -llvm::Optional -IdentifierNamingCheck::GetDeclFailureInfo(const NamedDecl *Decl, - const SourceManager &SM) const { - StyleKind SK = findStyleKind(Decl, NamingStyles, IgnoreMainLikeFunctions); - if (SK == SK_Invalid) - return None; - - if (!NamingStyles[SK]) +static llvm::Optional getFailureInfo( + StringRef Name, SourceLocation Location, + ArrayRef> NamingStyles, + StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit) { + if (SK == SK_Invalid || !NamingStyles[SK]) return None; - const NamingStyle &Style = *NamingStyles[SK]; - StringRef Name = Decl->getName(); + const IdentifierNamingCheck::NamingStyle &Style = *NamingStyles[SK]; if (matchesStyle(Name, Style)) return None; - std::string KindName = fixupWithCase(StyleNames[SK], CT_LowerCase); + std::string KindName = + fixupWithCase(StyleNames[SK], IdentifierNamingCheck::CT_LowerCase); std::replace(KindName.begin(), KindName.end(), '_', ' '); std::string Fixup = fixupWithStyle(Name, Style); if (StringRef(Fixup).equals(Name)) { if (!IgnoreFailedSplit) { - LLVM_DEBUG(llvm::dbgs() - << Decl->getBeginLoc().printToString(SM) - << llvm::format(": unable to split words for %s '%s'\n", - KindName.c_str(), Name.str().c_str())); + LLVM_DEBUG(Location.print(llvm::dbgs(), SM); + llvm::dbgs() + << llvm::formatv(": unable to split words for {0} '{1}'\n", + KindName, Name)); } return None; } - return FailureInfo{std::move(KindName), std::move(Fixup)}; + return RenamerClangTidyCheck::FailureInfo{std::move(KindName), + std::move(Fixup)}; +} + +llvm::Optional +IdentifierNamingCheck::GetDeclFailureInfo(const NamedDecl *Decl, + const SourceManager &SM) const { + SourceLocation Loc = Decl->getLocation(); + ArrayRef> NamingStyles = + getStyleForFile(SM.getFilename(Loc)); + + return getFailureInfo( + Decl->getName(), Loc, NamingStyles, + findStyleKind(Decl, NamingStyles, IgnoreMainLikeFunctions), SM, + IgnoreFailedSplit); } llvm::Optional IdentifierNamingCheck::GetMacroFailureInfo(const Token &MacroNameTok, const SourceManager &SM) const { - if (!NamingStyles[SK_MacroDefinition]) - return None; - - StringRef Name = MacroNameTok.getIdentifierInfo()->getName(); - const NamingStyle &Style = *NamingStyles[SK_MacroDefinition]; - if (matchesStyle(Name, Style)) - return None; - - std::string KindName = - fixupWithCase(StyleNames[SK_MacroDefinition], CT_LowerCase); - std::replace(KindName.begin(), KindName.end(), '_', ' '); + SourceLocation Loc = MacroNameTok.getLocation(); - std::string Fixup = fixupWithStyle(Name, Style); - if (StringRef(Fixup).equals(Name)) { - if (!IgnoreFailedSplit) { - LLVM_DEBUG(llvm::dbgs() - << MacroNameTok.getLocation().printToString(SM) - << llvm::format(": unable to split words for %s '%s'\n", - KindName.c_str(), Name.str().c_str())); - } - return None; - } - return FailureInfo{std::move(KindName), std::move(Fixup)}; + return getFailureInfo(MacroNameTok.getIdentifierInfo()->getName(), Loc, + getStyleForFile(SM.getFilename(Loc)), + SK_MacroDefinition, SM, IgnoreFailedSplit); } RenamerClangTidyCheck::DiagInfo IdentifierNamingCheck::GetDiagInfo(const NamingCheckId &ID, const NamingCheckFailure &Failure) const { return DiagInfo{"invalid case style for %0 '%1'", - [&](DiagnosticBuilder &diag) { - diag << Failure.Info.KindName << ID.second; + [&](DiagnosticBuilder &Diag) { + Diag << Failure.Info.KindName << ID.second; }}; } +ArrayRef> +IdentifierNamingCheck::getStyleForFile(StringRef FileName) const { + if (!GetConfigPerFile) + return MainFileStyle; + auto &Styles = NamingStylesCache[llvm::sys::path::parent_path(FileName)]; + if (Styles.empty()) { + ClangTidyOptions Options = Context->getOptionsForFile(FileName); + if (Options.Checks && GlobList(*Options.Checks).contains(CheckName)) + Styles = getNamingStyles({CheckName, Options.CheckOptions}); + else + Styles.resize(SK_Count, None); + } + return Styles; +} + } // namespace readability } // namespace tidy } // namespace clang diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h index 0f6c77b2c9a86..ad1c582d100bc 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IDENTIFIERNAMINGCHECK_H #include "../utils/RenamerClangTidyCheck.h" +#include "llvm/ADT/Optional.h" namespace clang { class MacroInfo; @@ -69,7 +70,17 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { DiagInfo GetDiagInfo(const NamingCheckId &ID, const NamingCheckFailure &Failure) const override; - std::vector> NamingStyles; + ArrayRef> + getStyleForFile(StringRef FileName) const; + + /// Stores the style options as a vector, indexed by the specified \ref + /// StyleKind, for a given directory. + mutable llvm::StringMap>> + NamingStylesCache; + ArrayRef> MainFileStyle; + ClangTidyContext *const Context; + const std::string CheckName; + const bool GetConfigPerFile; const bool IgnoreFailedSplit; const bool IgnoreMainLikeFunctions; }; diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index 040378d980f1a..2d67ca4a16180 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -157,6 +157,9 @@ void RenamerClangTidyCheck::addUsage( RenamerClangTidyCheck::NamingCheckFailure &Failure = NamingCheckFailures[Decl]; + if (!Failure.RawUsageLocs.insert(FixLocation.getRawEncoding()).second) + return; + if (!Failure.ShouldFix()) return; @@ -165,8 +168,6 @@ void RenamerClangTidyCheck::addUsage( if (!utils::rangeCanBeFixed(Range, SourceMgr)) Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro; - - Failure.RawUsageLocs.insert(FixLocation.getRawEncoding()); } void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range, diff --git a/clang-tools-extra/clangd/FindSymbols.cpp b/clang-tools-extra/clangd/FindSymbols.cpp index f5d6a95aa713d..2471656988250 100644 --- a/clang-tools-extra/clangd/FindSymbols.cpp +++ b/clang-tools-extra/clangd/FindSymbols.cpp @@ -188,7 +188,7 @@ class DocumentOutline { } private: - enum class VisitKind { No, OnlyDecl, DeclAndChildren }; + enum class VisitKind { No, OnlyDecl, OnlyChildren, DeclAndChildren }; void traverseDecl(Decl *D, std::vector &Results) { if (auto *Templ = llvm::dyn_cast(D)) { @@ -196,18 +196,25 @@ class DocumentOutline { if (auto *TD = Templ->getTemplatedDecl()) D = TD; } - auto *ND = llvm::dyn_cast(D); - if (!ND) - return; - VisitKind Visit = shouldVisit(ND); + + VisitKind Visit = shouldVisit(D); if (Visit == VisitKind::No) return; - llvm::Optional Sym = declToSym(AST.getASTContext(), *ND); + + if (Visit == VisitKind::OnlyChildren) + return traverseChildren(D, Results); + + auto *ND = llvm::cast(D); + auto Sym = declToSym(AST.getASTContext(), *ND); if (!Sym) return; - if (Visit == VisitKind::DeclAndChildren) - traverseChildren(D, Sym->children); Results.push_back(std::move(*Sym)); + + if (Visit == VisitKind::OnlyDecl) + return; + + assert(Visit == VisitKind::DeclAndChildren && "Unexpected VisitKind"); + traverseChildren(ND, Results.back().children); } void traverseChildren(Decl *D, std::vector &Results) { @@ -218,10 +225,16 @@ class DocumentOutline { traverseDecl(C, Results); } - VisitKind shouldVisit(NamedDecl *D) { + VisitKind shouldVisit(Decl *D) { if (D->isImplicit()) return VisitKind::No; + if (llvm::isa(D) || llvm::isa(D)) + return VisitKind::OnlyChildren; + + if (!llvm::isa(D)) + return VisitKind::No; + if (auto Func = llvm::dyn_cast(D)) { // Some functions are implicit template instantiations, those should be // ignored. diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index a346d6b662e9a..e4d2dddb4b5d3 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -460,6 +460,12 @@ struct TargetFinder { void VisitPseudoObjectExpr(const PseudoObjectExpr *POE) { Outer.add(POE->getSyntacticForm(), Flags); } + void VisitCXXNewExpr(const CXXNewExpr *CNE) { + Outer.add(CNE->getOperatorNew(), Flags); + } + void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE) { + Outer.add(CDE->getOperatorDelete(), Flags); + } }; Visitor(*this, Flags).Visit(S); } diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index cf747b607f4a1..26653aa409d7d 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -238,6 +238,10 @@ locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier, llvm::DenseMap ResultIndex; auto AddResultDecl = [&](const NamedDecl *D) { + // FIXME: Canonical declarations of some symbols might refer to built-in + // decls with possibly-invalid source locations (e.g. global new operator). + // In such cases we should pick up a redecl with valid source location + // instead of failing. D = llvm::cast(D->getCanonicalDecl()); auto Loc = makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath); @@ -405,15 +409,17 @@ locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, log("locateSymbolNamedTextuallyAt: {0}", MaybeDeclLoc.takeError()); return; } - Location DeclLoc = *MaybeDeclLoc; - Location DefLoc; + LocatedSymbol Located; + Located.PreferredDeclaration = *MaybeDeclLoc; + Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str(); if (Sym.Definition) { auto MaybeDefLoc = indexToLSPLocation(Sym.Definition, MainFilePath); if (!MaybeDefLoc) { log("locateSymbolNamedTextuallyAt: {0}", MaybeDefLoc.takeError()); return; } - DefLoc = *MaybeDefLoc; + Located.PreferredDeclaration = *MaybeDefLoc; + Located.Definition = *MaybeDefLoc; } if (ScoredResults.size() >= 3) { @@ -424,11 +430,6 @@ locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, return; } - LocatedSymbol Located; - Located.Name = (Sym.Name + Sym.TemplateSpecializationArgs).str(); - Located.PreferredDeclaration = bool(Sym.Definition) ? DefLoc : DeclLoc; - Located.Definition = DefLoc; - SymbolQualitySignals Quality; Quality.merge(Sym); SymbolRelevanceSignals Relevance; diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp index e28a2c46c374a..698d2a406811a 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineInline.cpp @@ -339,7 +339,7 @@ renameParameters(const FunctionDecl *Dest, const FunctionDecl *Source) { // specialization. const FunctionDecl *findTarget(const FunctionDecl *FD) { auto CanonDecl = FD->getCanonicalDecl(); - if (!FD->isFunctionTemplateSpecialization()) + if (!FD->isFunctionTemplateSpecialization() || CanonDecl == FD) return CanonDecl; // For specializations CanonicalDecl is the TemplatedDecl, which is not the // target we want to inline into. Instead we traverse previous decls to find diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index d37d377407991..9f68e248197e7 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -122,9 +122,8 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD, if (!OrigFuncRange) return llvm::createStringError(llvm::inconvertibleErrorCode(), "Couldn't get range for function."); - // Include template parameter list. - if (auto *FTD = FD->getDescribedFunctionTemplate()) - OrigFuncRange->setBegin(FTD->getBeginLoc()); + assert(!FD->getDescribedFunctionTemplate() && + "Define out-of-line doesn't apply to function templates."); // Get new begin and end positions for the qualified function definition. unsigned FuncBegin = SM.getFileOffset(OrigFuncRange->getBegin()); @@ -387,6 +386,13 @@ class DefineOutline : public Tweak { Source->isOutOfLine()) return false; + // Bail out if this is a function template or specialization, as their + // definitions need to be visible in all including translation units. + if (auto *PT = Source->getDescribedFunctionTemplate()) + return false; + if (auto *TSI = Source->getTemplateSpecializationInfo()) + return false; + // Bail out in templated classes, as it is hard to spell the class name, i.e // if the template parameter is unnamed. if (auto *MD = llvm::dyn_cast(Source)) { diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp index dd62670646c41..895afbb116f18 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp @@ -480,17 +480,6 @@ CapturedZoneInfo captureZoneInfo(const ExtractionZone &ExtZone) { CurNumberOfSwitch += Increment; } - // Decrement CurNumberOf{NestedLoops,Switch} if statement is {Loop,Switch} - // and inside Extraction Zone. - void decrementLoopSwitchCounters(Stmt *S) { - if (CurrentLocation != ZoneRelative::Inside) - return; - if (isLoop(S)) - CurNumberOfNestedLoops--; - else if (isa(S)) - CurNumberOfSwitch--; - } - bool VisitDecl(Decl *D) { Info.createDeclInfo(D, CurrentLocation); return true; diff --git a/clang-tools-extra/clangd/refactor/tweaks/SwapIfBranches.cpp b/clang-tools-extra/clangd/refactor/tweaks/SwapIfBranches.cpp index 2422743019a13..d6966e699fdbc 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/SwapIfBranches.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/SwapIfBranches.cpp @@ -40,6 +40,7 @@ class SwapIfBranches : public Tweak { Expected apply(const Selection &Inputs) override; std::string title() const override { return "Swap if branches"; } Intent intent() const override { return Refactor; } + bool hidden() const override { return true; } private: const IfStmt *If = nullptr; diff --git a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp index 07c42fcf20304..8576e11a5f21a 100644 --- a/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindSymbolsTests.cpp @@ -429,6 +429,40 @@ TEST(DocumentSymbols, ExternSymbol) { EXPECT_THAT(getSymbols(TU.build()), IsEmpty()); } +TEST(DocumentSymbols, ExternContext) { + TestTU TU; + TU.Code = R"cpp( + extern "C" { + void foo(); + class Foo {}; + } + namespace ns { + extern "C" { + void bar(); + class Bar {}; + } + })cpp"; + + EXPECT_THAT(getSymbols(TU.build()), + ElementsAre(WithName("foo"), WithName("Foo"), + AllOf(WithName("ns"), + Children(WithName("bar"), WithName("Bar"))))); +} + +TEST(DocumentSymbols, ExportContext) { + TestTU TU; + TU.ExtraArgs = {"-std=c++20"}; + TU.Code = R"cpp( + export module test; + export { + void foo(); + class Foo {}; + })cpp"; + + EXPECT_THAT(getSymbols(TU.build()), + ElementsAre(WithName("foo"), WithName("Foo"))); +} + TEST(DocumentSymbols, NoLocals) { TestTU TU; TU.Code = R"cpp( diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 92095e871e201..3421b9cec2d30 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -405,6 +405,11 @@ TEST_F(TargetDeclTest, ClassTemplate) { } TEST_F(TargetDeclTest, Concept) { + Flags.push_back("-std=c++20"); + + // FIXME: Should we truncate the pretty-printed form of a concept decl + // somewhere? + Code = R"cpp( template concept Fooable = requires (T t) { t.foo(); }; @@ -414,12 +419,20 @@ TEST_F(TargetDeclTest, Concept) { t.foo(); } )cpp"; - Flags.push_back("-std=c++20"); EXPECT_DECLS( "ConceptSpecializationExpr", - // FIXME: Should we truncate the pretty-printed form of a concept decl - // somewhere? {"template concept Fooable = requires (T t) { t.foo(); };"}); + + // trailing requires clause + Code = R"cpp( + template + concept Fooable = true; + + template + void foo() requires [[Fooable]]; + )cpp"; + EXPECT_DECLS("ConceptSpecializationExpr", + {"template concept Fooable = true;"}); } TEST_F(TargetDeclTest, FunctionTemplate) { @@ -535,6 +548,7 @@ TEST_F(TargetDeclTest, OverloadExpr) { // FIXME: Auto-completion in a template requires disabling delayed template // parsing. Flags = {"-fno-delayed-template-parsing"}; + Flags.push_back("--target=x86_64-pc-linux-gnu"); Code = R"cpp( void func(int*); @@ -559,6 +573,36 @@ TEST_F(TargetDeclTest, OverloadExpr) { }; )cpp"; EXPECT_DECLS("UnresolvedMemberExpr", "void func(int *)", "void func(char *)"); + + Code = R"cpp( + struct X { + static void *operator new(unsigned long); + }; + auto* k = [[new]] X(); + )cpp"; + EXPECT_DECLS("CXXNewExpr", "static void *operator new(unsigned long)"); + Code = R"cpp( + void *operator new(unsigned long); + auto* k = [[new]] int(); + )cpp"; + EXPECT_DECLS("CXXNewExpr", "void *operator new(unsigned long)"); + + Code = R"cpp( + struct X { + static void operator delete(void *) noexcept; + }; + void k(X* x) { + [[delete]] x; + } + )cpp"; + EXPECT_DECLS("CXXDeleteExpr", "static void operator delete(void *) noexcept"); + Code = R"cpp( + void operator delete(void *) noexcept; + void k(int* x) { + [[delete]] x; + } + )cpp"; + EXPECT_DECLS("CXXDeleteExpr", "void operator delete(void *) noexcept"); } TEST_F(TargetDeclTest, DependentExprs) { diff --git a/clang-tools-extra/clangd/unittests/TweakTests.cpp b/clang-tools-extra/clangd/unittests/TweakTests.cpp index 319d9e088c2d8..200a53c690b69 100644 --- a/clang-tools-extra/clangd/unittests/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp @@ -1093,6 +1093,11 @@ TEST_F(DefineInlineTest, TemplateSpec) { template<> void f^oo() { bar(); })cpp"); + EXPECT_UNAVAILABLE(R"cpp( + namespace bar { + template void f^oo() {} + template void foo(); + })cpp"); } TEST_F(DefineInlineTest, CheckForCanonDecl) { @@ -2003,6 +2008,13 @@ TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) { EXPECT_UNAVAILABLE(R"cpp( template struct Foo { void fo^o(){} }; )cpp"); + + // Not available on function templates and specializations, as definition must + // be visible to all translation units. + EXPECT_UNAVAILABLE(R"cpp( + template void fo^o() {}; + template <> void fo^o() {}; + )cpp"); } TEST_F(DefineOutlineTest, FailsWithoutSource) { @@ -2032,27 +2044,6 @@ TEST_F(DefineOutlineTest, ApplyTest) { "void foo() ;", "void foo() { return; }", }, - // Templated function. - { - "template void fo^o(T, T x) { return; }", - "template void foo(T, T x) ;", - "template void foo(T, T x) { return; }", - }, - { - "template void fo^o() { return; }", - "template void foo() ;", - "template void foo() { return; }", - }, - // Template specialization. - { - R"cpp( - template void foo(); - template <> void fo^o() { return; })cpp", - R"cpp( - template void foo(); - template <> void foo() ;)cpp", - "template <> void foo() { return; }", - }, // Default args. { "void fo^o(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) {}", diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index 0a8f85ed53176..c9c115fd19d83 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -41,6 +41,7 @@ using ::testing::ElementsAre; using ::testing::Eq; using ::testing::IsEmpty; using ::testing::Matcher; +using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAreArray; MATCHER_P2(FileRange, File, Range, "") { @@ -264,19 +265,23 @@ MATCHER_P3(Sym, Name, Decl, DefOrNone, "") { << llvm::to_string(arg.PreferredDeclaration); return false; } + if (!Def && !arg.Definition) + return true; if (Def && !arg.Definition) { *result_listener << "Has no definition"; return false; } - if (Def && arg.Definition->range != *Def) { + if (!Def && arg.Definition) { + *result_listener << "Definition is " << llvm::to_string(arg.Definition); + return false; + } + if (arg.Definition->range != *Def) { *result_listener << "Definition is " << llvm::to_string(arg.Definition); return false; } return true; } -::testing::Matcher Sym(std::string Name, Range Decl) { - return Sym(Name, Decl, llvm::None); -} + MATCHER_P(Sym, Name, "") { return arg.Name == Name; } MATCHER_P(RangeIs, R, "") { return arg.range == R; } @@ -771,7 +776,7 @@ TEST(LocateSymbol, TextualSmoke) { auto AST = TU.build(); auto Index = TU.index(); EXPECT_THAT(locateSymbolAt(AST, T.point(), Index.get()), - ElementsAre(Sym("MyClass", T.range()))); + ElementsAre(Sym("MyClass", T.range(), T.range()))); } TEST(LocateSymbol, Textual) { @@ -891,18 +896,20 @@ TEST(LocateSymbol, Ambiguous) { // FIXME: Target the constructor as well. EXPECT_THAT(locateSymbolAt(AST, T.point("9")), ElementsAre(Sym("Foo"))); EXPECT_THAT(locateSymbolAt(AST, T.point("10")), - ElementsAre(Sym("Foo", T.range("ConstructorLoc")))); + ElementsAre(Sym("Foo", T.range("ConstructorLoc"), llvm::None))); EXPECT_THAT(locateSymbolAt(AST, T.point("11")), - ElementsAre(Sym("Foo", T.range("ConstructorLoc")))); + ElementsAre(Sym("Foo", T.range("ConstructorLoc"), llvm::None))); // These assertions are unordered because the order comes from // CXXRecordDecl::lookupDependentName() which doesn't appear to provide // an order guarantee. EXPECT_THAT(locateSymbolAt(AST, T.point("12")), - UnorderedElementsAre(Sym("bar", T.range("NonstaticOverload1")), - Sym("bar", T.range("NonstaticOverload2")))); - EXPECT_THAT(locateSymbolAt(AST, T.point("13")), - UnorderedElementsAre(Sym("baz", T.range("StaticOverload1")), - Sym("baz", T.range("StaticOverload2")))); + UnorderedElementsAre( + Sym("bar", T.range("NonstaticOverload1"), llvm::None), + Sym("bar", T.range("NonstaticOverload2"), llvm::None))); + EXPECT_THAT( + locateSymbolAt(AST, T.point("13")), + UnorderedElementsAre(Sym("baz", T.range("StaticOverload1"), llvm::None), + Sym("baz", T.range("StaticOverload2"), llvm::None))); } TEST(LocateSymbol, TextualDependent) { @@ -932,9 +939,10 @@ TEST(LocateSymbol, TextualDependent) { // interaction between locateASTReferent() and // locateSymbolNamedTextuallyAt(). auto Results = locateSymbolAt(AST, Source.point(), Index.get()); - EXPECT_THAT(Results, UnorderedElementsAre( - Sym("uniqueMethodName", Header.range("FooLoc")), - Sym("uniqueMethodName", Header.range("BarLoc")))); + EXPECT_THAT(Results, + UnorderedElementsAre( + Sym("uniqueMethodName", Header.range("FooLoc"), llvm::None), + Sym("uniqueMethodName", Header.range("BarLoc"), llvm::None))); } TEST(LocateSymbol, TemplateTypedefs) { @@ -992,20 +1000,23 @@ int [[bar_not_preamble]]; auto Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p1")); EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo", SourceAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo", SourceAnnotations.range(), + SourceAnnotations.range()))); // Go to a definition in header_in_preamble.h. Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p2")); EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error"; EXPECT_THAT( *Locations, - ElementsAre(Sym("bar_preamble", HeaderInPreambleAnnotations.range()))); + ElementsAre(Sym("bar_preamble", HeaderInPreambleAnnotations.range(), + HeaderInPreambleAnnotations.range()))); // Go to a definition in header_not_in_preamble.h. Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("p3")); EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error"; EXPECT_THAT(*Locations, ElementsAre(Sym("bar_not_preamble", + HeaderNotInPreambleAnnotations.range(), HeaderNotInPreambleAnnotations.range()))); } @@ -1039,21 +1050,25 @@ TEST(GoToInclude, All) { // Test include in preamble. auto Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point()); ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(), + HeaderAnnotations.range()))); // Test include in preamble, last char. Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("2")); ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(), + HeaderAnnotations.range()))); Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("3")); ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(), + HeaderAnnotations.range()))); // Test include outside of preamble. Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("6")); ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(), + HeaderAnnotations.range()))); // Test a few positions that do not result in Locations. Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("4")); @@ -1062,11 +1077,13 @@ TEST(GoToInclude, All) { Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("5")); ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(), + HeaderAnnotations.range()))); Locations = runLocateSymbolAt(Server, FooCpp, SourceAnnotations.point("7")); ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(), + HeaderAnnotations.range()))); // Objective C #import directive. Annotations ObjC(R"objc( @@ -1078,7 +1095,8 @@ TEST(GoToInclude, All) { Server.addDocument(FooM, ObjC.code()); Locations = runLocateSymbolAt(Server, FooM, ObjC.point()); ASSERT_TRUE(bool(Locations)) << "locateSymbolAt returned an error"; - EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range()))); + EXPECT_THAT(*Locations, ElementsAre(Sym("foo.h", HeaderAnnotations.range(), + HeaderAnnotations.range()))); } TEST(LocateSymbol, WithPreamble) { @@ -1103,7 +1121,7 @@ TEST(LocateSymbol, WithPreamble) { // LocateSymbol goes to a #include file: the result comes from the preamble. EXPECT_THAT( cantFail(runLocateSymbolAt(Server, FooCpp, FooWithHeader.point())), - ElementsAre(Sym("foo.h", FooHeader.range()))); + ElementsAre(Sym("foo.h", FooHeader.range(), FooHeader.range()))); // Only preamble is built, and no AST is built in this request. Server.addDocument(FooCpp, FooWithoutHeader.code(), "null", @@ -1112,7 +1130,7 @@ TEST(LocateSymbol, WithPreamble) { // stale one. EXPECT_THAT( cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())), - ElementsAre(Sym("foo", FooWithoutHeader.range()))); + ElementsAre(Sym("foo", FooWithoutHeader.range(), llvm::None))); // Reset test environment. runAddDocument(Server, FooCpp, FooWithHeader.code()); @@ -1122,7 +1140,7 @@ TEST(LocateSymbol, WithPreamble) { // Use the AST being built in above request. EXPECT_THAT( cantFail(runLocateSymbolAt(Server, FooCpp, FooWithoutHeader.point())), - ElementsAre(Sym("foo", FooWithoutHeader.range()))); + ElementsAre(Sym("foo", FooWithoutHeader.range(), llvm::None))); } TEST(LocateSymbol, NearbyTokenSmoke) { @@ -1133,7 +1151,7 @@ TEST(LocateSymbol, NearbyTokenSmoke) { auto AST = TestTU::withCode(T.code()).build(); // We don't pass an index, so can't hit index-based fallback. EXPECT_THAT(locateSymbolAt(AST, T.point()), - ElementsAre(Sym("err", T.range()))); + ElementsAre(Sym("err", T.range(), T.range()))); } TEST(LocateSymbol, NearbyIdentifier) { diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 1d447938eae0c..89f6a50888ccc 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -67,7 +67,14 @@ The improvements are... Improvements to clang-tidy -------------------------- -The improvements are... +Changes in existing checks +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Improved :doc:`readability-identifier-naming + ` check. + + Added an option `GetConfigPerFile` to support including files which use + different naming styles. Improvements to include-fixer ----------------------------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst b/clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst index eefa5234fb211..9eec3c03f7d7d 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability-identifier-naming.rst @@ -51,6 +51,7 @@ The following options are describe below: - :option:`EnumCase`, :option:`EnumPrefix`, :option:`EnumSuffix` - :option:`EnumConstantCase`, :option:`EnumConstantPrefix`, :option:`EnumConstantSuffix` - :option:`FunctionCase`, :option:`FunctionPrefix`, :option:`FunctionSuffix` + - :option:`GetConfigPerFile` - :option:`GlobalConstantCase`, :option:`GlobalConstantPrefix`, :option:`GlobalConstantSuffix` - :option:`GlobalConstantPointerCase`, :option:`GlobalConstantPointerPrefix`, :option:`GlobalConstantPointerSuffix` - :option:`GlobalFunctionCase`, :option:`GlobalFunctionPrefix`, :option:`GlobalFunctionSuffix` @@ -713,6 +714,13 @@ After: char pre_my_function_string_post(); +.. option:: GetConfigPerFile + + When `true` the check will look for the configuration for where an + identifier is declared. Useful for when included header files use a + different style. + Default value is `true`. + .. option:: GlobalConstantCase When defined, the check will ensure global constant names conform to the diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style-disabled/.clang-tidy b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style-disabled/.clang-tidy new file mode 100644 index 0000000000000..6a704df8b7b19 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style-disabled/.clang-tidy @@ -0,0 +1,5 @@ +Checks: -readability-identifier-naming +CheckOptions: + - key: readability-identifier-naming.GlobalFunctionCase + value: lower_case + diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style-disabled/header.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style-disabled/header.h new file mode 100644 index 0000000000000..e863f70f7fcb2 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style-disabled/header.h @@ -0,0 +1,3 @@ +void disabled_style_1(); +void disabledStyle2(); +void DISABLED_STYLE_3(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style1/.clang-tidy b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style1/.clang-tidy new file mode 100644 index 0000000000000..85af9672b61d3 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style1/.clang-tidy @@ -0,0 +1,5 @@ +Checks: readability-identifier-naming +CheckOptions: + - key: readability-identifier-naming.GlobalFunctionCase + value: lower_case + diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style1/header.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style1/header.h new file mode 100644 index 0000000000000..b170bed7c3f60 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style1/header.h @@ -0,0 +1,5 @@ + + +void style_first_good(); + +void styleFirstBad(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style2/.clang-tidy b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style2/.clang-tidy new file mode 100644 index 0000000000000..b2e67ea9c87b5 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style2/.clang-tidy @@ -0,0 +1,5 @@ +Checks: readability-identifier-naming +CheckOptions: + - key: readability-identifier-naming.GlobalFunctionCase + value: UPPER_CASE + diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style2/header.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style2/header.h new file mode 100644 index 0000000000000..6b78ad82a1fdd --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/readability-identifier-naming/global-style2/header.h @@ -0,0 +1,5 @@ + + +void STYLE_SECOND_GOOD(); + +void styleSecondBad(); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-bad-signal-to-kill-thread-sigterm-not-a-literal.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-bad-signal-to-kill-thread-sigterm-not-a-literal.cpp new file mode 100644 index 0000000000000..f96f270dbf29d --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-bad-signal-to-kill-thread-sigterm-not-a-literal.cpp @@ -0,0 +1,10 @@ +// RUN: clang-tidy %s --checks=-*,bugprone-bad-signal-to-kill-thread -- | count 0 + +#define SIGTERM ((unsigned)15) // no-crash +using pthread_t = int; +int pthread_kill(pthread_t thread, int sig); + +int func() { + pthread_t thread; + return pthread_kill(thread, 0); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-bad-signal-to-kill-thread-undef-sigterm.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-bad-signal-to-kill-thread-undef-sigterm.cpp new file mode 100644 index 0000000000000..7c2ae16a08e86 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-bad-signal-to-kill-thread-undef-sigterm.cpp @@ -0,0 +1,11 @@ +// RUN: clang-tidy %s --checks=-*,bugprone-bad-signal-to-kill-thread -- | count 0 + +#define SIGTERM 15 +#undef SIGTERM // no-crash +using pthread_t = int; +int pthread_kill(pthread_t thread, int sig); + +int func() { + pthread_t thread; + return pthread_kill(thread, 0); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-bool-pointer-implicit-conversion.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-bool-pointer-implicit-conversion.cpp index 37c6939b590f0..926fd68321a7e 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone-bool-pointer-implicit-conversion.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-bool-pointer-implicit-conversion.cpp @@ -74,9 +74,31 @@ void foo() { bool *b; } d = { SomeFunction() }; - if (d.b) + if (d.b) { + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: dubious check of 'bool *' against 'nullptr' + // CHECK-FIXES: if (*d.b) { + } + + if (d.b) { (void)*d.b; // no-warning + } -#define CHECK(b) if (b) {} +#define CHECK(b) \ + if (b) { \ + } CHECK(c) } + +struct H { + bool *b; + void foo() const { + if (b) { + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: dubious check of 'bool *' against 'nullptr' + // CHECK-FIXES: if (*b) { + } + + if (b) { + (void)*b; // no-warning + } + } +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming-multiple-styles.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming-multiple-styles.cpp new file mode 100644 index 0000000000000..54880d2ca3d0a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming-multiple-styles.cpp @@ -0,0 +1,64 @@ +// Setup header directory + +// RUN: rm -rf %theaders +// RUN: mkdir %theaders +// RUN: cp -R %S/Inputs/readability-identifier-naming/. %theaders + +// C++11 isn't explicitly required, but failing to specify a standard means the +// check will run multiple times for different standards. This will cause the +// second test to fail as the header file will be changed during the first run. +// InheritParentConfig is needed to look for the clang-tidy configuration files. + +// RUN: %check_clang_tidy -check-suffixes=ENABLED,SHARED -std=c++11 %s \ +// RUN: readability-identifier-naming %t -- \ +// RUN: -config='{ InheritParentConfig: true, CheckOptions: [ \ +// RUN: {key: readability-identifier-naming.FunctionCase, value: camelBack}, \ +// RUN: {key: readability-identifier-naming.GetConfigPerFile, value: true} \ +// RUN: ]}' -header-filter='.*' -- -I%theaders + +// On DISABLED run, everything should be made 'camelBack'. + +// RUN: cp -R %S/Inputs/readability-identifier-naming/. %theaders +// RUN: %check_clang_tidy -check-suffixes=DISABLED,SHARED -std=c++11 %s \ +// RUN: readability-identifier-naming %t -- \ +// RUN: -config='{ InheritParentConfig: true, CheckOptions: [ \ +// RUN: {key: readability-identifier-naming.FunctionCase, value: camelBack}, \ +// RUN: {key: readability-identifier-naming.GetConfigPerFile, value: false} \ +// RUN: ]}' -header-filter='.*' -- -I%theaders + +#include "global-style-disabled/header.h" +#include "global-style1/header.h" +#include "global-style2/header.h" +// CHECK-MESSAGES-ENABLED-DAG: global-style1/header.h:5:6: warning: invalid case style for global function 'styleFirstBad' +// CHECK-MESSAGES-ENABLED-DAG: global-style2/header.h:5:6: warning: invalid case style for global function 'styleSecondBad' +// CHECK-MESSAGES-DISABLED-DAG: global-style1/header.h:3:6: warning: invalid case style for function 'style_first_good' +// CHECK-MESSAGES-DISABLED-DAG: global-style2/header.h:3:6: warning: invalid case style for function 'STYLE_SECOND_GOOD' +// CHECK-MESSAGES-DISABLED-DAG: global-style-disabled/header.h:1:6: warning: invalid case style for function 'disabled_style_1' +// CHECK-MESSAGES-DISABLED-DAG: global-style-disabled/header.h:3:6: warning: invalid case style for function 'DISABLED_STYLE_3' + +void goodStyle() { + style_first_good(); + STYLE_SECOND_GOOD(); + // CHECK-FIXES-DISABLED: styleFirstGood(); + // CHECK-FIXES-DISABLED-NEXT: styleSecondGood(); +} +// CHECK-MESSAGES-SHARED-DAG: :[[@LINE+1]]:6: warning: invalid case style for function 'bad_style' +void bad_style() { + styleFirstBad(); + styleSecondBad(); +} +// CHECK-FIXES-SHARED: void badStyle() { +// CHECK-FIXES-DISABLED-NEXT: styleFirstBad(); +// CHECK-FIXES-ENABLED-NEXT: style_first_bad(); +// CHECK-FIXES-DISABLED-NEXT: styleSecondBad(); +// CHECK-FIXES-ENABLED-NEXT: STYLE_SECOND_BAD(); +// CHECK-FIXES-SHARED-NEXT: } + +void expectNoStyle() { + disabled_style_1(); + disabledStyle2(); + DISABLED_STYLE_3(); + // CHECK-FIXES-DISABLED: disabledStyle1(); + // CHECK-FIXES-DISABLED-NEXT: disabledStyle2(); + // CHECK-FIXES-DISABLED-NEXT: disabledStyle3(); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp index 24c1c4270dec8..fed362bbecdec 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-identifier-naming.cpp @@ -578,3 +578,8 @@ void Foo() { #undef M1 #undef DUP } // namespace scratchspace + +template +auto GetRes(type_t& Param) -> decltype(Param.res()); +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: invalid case style for parameter 'Param' +// CHECK-FIXES: auto GetRes(type_t& a_param) -> decltype(a_param.res()); diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 277550431529e..56b207916ff2f 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -121,6 +121,8 @@ if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) include(LLVMDistributionSupport) set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}") + set(BUG_REPORT_URL "${LLVM_PACKAGE_BUGREPORT}" CACHE STRING + "Default URL where bug reports are to be submitted.") if (NOT DEFINED LLVM_INCLUDE_TESTS) set(LLVM_INCLUDE_TESTS ON) @@ -257,7 +259,7 @@ set(DEFAULT_SYSROOT "" CACHE STRING set(ENABLE_LINKER_BUILD_ID OFF CACHE BOOL "pass --build-id to ld") -set(ENABLE_X86_RELAX_RELOCATIONS OFF CACHE BOOL +set(ENABLE_X86_RELAX_RELOCATIONS ON CACHE BOOL "enable x86 relax relocations by default") set(ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER FALSE CACHE BOOL @@ -422,15 +424,15 @@ if (APPLE) RESULT_VARIABLE HAD_ERROR OUTPUT_VARIABLE LD_V_OUTPUT ) - if (NOT HAD_ERROR) - if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*") - string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT}) - elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*") - string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT}) - endif() - else() + if (HAD_ERROR) message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}") endif() + if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*") + string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT}) + elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*") + string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT}) + endif() + message(STATUS "Host linker version: ${HOST_LINK_VERSION}") endif() include(CMakeParseArguments) diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst index 1613c8e453184..8eb010eae2659 100644 --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -1016,7 +1016,7 @@ Flags controlling how ``#include``\s are resolved to files. .. option:: -I, --include-directory , --include-directory= -Add directory to include search path +Add directory to include search path. If there are multiple -I options, these directories are searched in the order they are given before the standard system directories are searched. If the same directory is in the SYSTEM include search paths, for example if also specified with -isystem, the -I option will be ignored .. option:: -I-, --include-barrier diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst index 28fbd7baebb24..e63d91586b954 100644 --- a/clang/docs/OpenMPSupport.rst +++ b/clang/docs/OpenMPSupport.rst @@ -221,6 +221,8 @@ implementation. +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | device extension | pointer attachment | :none:`unclaimed` | | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ +| device extension | map clause reordering based on map types | :none:`unclaimed` | | ++------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | atomic extension | hints for the atomic construct | :good:`done` | D51233 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | base language | C11 support | :good:`done` | | @@ -266,9 +268,11 @@ want to help with the implementation. +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | misc extension | default(firstprivate) & default(private) | :part:`partial` | firstprivate done: D75591 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ -| loop extension | Loop tiling transformation | :part:`claimed` | | +| loop extension | Loop tiling transformation | :part:`worked on` | D76342 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ -| device extension | 'present' map type modifier | :part:`mostly done` | D83061, D83062, D84422 | +| device extension | 'present' map type modifier | :good:`done` | D83061, D83062, D84422 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | device extension | 'present' motion modifier | :good:`done` | D84711, D84712 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ +| device extension | map clause reordering reordering based on 'present' modifier | :none:`unclaimed` | | ++------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9274081c4d62c..03eca8a26843e 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -100,7 +100,10 @@ future versions of Clang. Modified Compiler Flags ----------------------- -- ... +- On ELF, ``-gz`` now defaults to ``-gz=zlib`` with the integrated assembler. + It produces ``SHF_COMPRESSED`` style compression of debug information. GNU + binutils 2.26 or newer, or lld is required to link produced object files. Use + ``-gz=zlib-gnu`` to get the old behavior. New Pragmas in Clang -------------------- diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 1583da7aff098..3b378f735ebcc 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1423,6 +1423,25 @@ Raw pointers and references to uncounted types can't be used as class members. O // ... }; +.. _webkit-UncountedLambdaCapturesChecker: + +webkit.UncountedLambdaCapturesChecker +""""""""""""""""""""""""""""""""""""" +Raw pointers and references to uncounted types can't be captured in lambdas. Only ref-counted types are allowed. + +.. code-block:: cpp + + struct RefCntbl { + void ref() {} + void deref() {} + }; + + void foo(RefCntbl* a, RefCntbl& b) { + [&, a](){ // warn about 'a' + do_something(b); // warn about 'b' + }; + }; + .. _alpha-checkers: Experimental Checkers diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index ed33b2d6394f9..e875f7ed960b8 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -43,6 +43,7 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/MapVector.h" @@ -1004,6 +1005,9 @@ class ASTContext : public RefCountedBase { // Implicitly-declared type 'struct _GUID'. mutable TagDecl *MSGuidTagDecl = nullptr; + /// Keep track of CUDA/HIP static device variables referenced by host code. + llvm::DenseSet CUDAStaticDeviceVarReferencedByHost; + ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins); ASTContext(const ASTContext &) = delete; @@ -3035,6 +3039,9 @@ OPT_LIST(V) /// Return a new OMPTraitInfo object owned by this context. OMPTraitInfo &getNewOMPTraitInfo(); + /// Whether a C++ static variable should be externalized. + bool shouldExternalizeStaticVar(const Decl *D) const; + private: /// All OMPTraitInfo objects live in this collection, one per /// `pragma omp [begin] declare variant` directive. diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 0cfc852016131..e34d7c8db5445 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -265,6 +265,8 @@ class NamedDecl : public Decl { // FIXME: Deprecated, move clients to getName(). std::string getNameAsString() const { return Name.getAsString(); } + /// Pretty-print the unqualified name of this declaration. Can be overloaded + /// by derived classes to provide a more user-friendly name when appropriate. virtual void printName(raw_ostream &os) const; /// Get the actual, stored name of the declaration, which may be a special diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h old mode 100755 new mode 100644 index e9c4879b41e89..4feb1d45251d5 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -204,10 +204,6 @@ class TemplateParameterList final bool OmitTemplateKW = false) const; void print(raw_ostream &Out, const ASTContext &Context, const PrintingPolicy &Policy, bool OmitTemplateKW = false) const; - -public: - // FIXME: workaround for MSVC 2013; remove when no longer needed - using FixedSizeStorageOwner = TrailingObjects::FixedSizeStorageOwner; }; /// Stores a list of template parameters and the associated diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 8e8084aec3c18..f68a5dbfc2a0d 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -295,6 +295,7 @@ class TextNodeDumper void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); void VisitOMPIteratorExpr(const OMPIteratorExpr *Node); + void VisitConceptSpecializationExpr(const ConceptSpecializationExpr *Node); void VisitRValueReferenceType(const ReferenceType *T); void VisitArrayType(const ArrayType *T); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 4cf06441fb7b1..b976ca2c7303b 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1687,19 +1687,6 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { uint32_t NumElements; }; - class ConstantMatrixTypeBitfields { - friend class ConstantMatrixType; - - unsigned : NumTypeBits; - - /// Number of rows and columns. Using 20 bits allows supporting very large - /// matrixes, while keeping 24 bits to accommodate NumTypeBits. - unsigned NumRows : 20; - unsigned NumColumns : 20; - - static constexpr uint32_t MaxElementsPerDimension = (1 << 20) - 1; - }; - class AttributedTypeBitfields { friend class AttributedType; @@ -1809,46 +1796,11 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { TypeWithKeywordBitfields TypeWithKeywordBits; ElaboratedTypeBitfields ElaboratedTypeBits; VectorTypeBitfields VectorTypeBits; - ConstantMatrixTypeBitfields ConstantMatrixTypeBits; SubstTemplateTypeParmPackTypeBitfields SubstTemplateTypeParmPackTypeBits; TemplateSpecializationTypeBitfields TemplateSpecializationTypeBits; DependentTemplateSpecializationTypeBitfields DependentTemplateSpecializationTypeBits; PackExpansionTypeBitfields PackExpansionTypeBits; - - static_assert(sizeof(TypeBitfields) <= 8, - "TypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ArrayTypeBitfields) <= 8, - "ArrayTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(AttributedTypeBitfields) <= 8, - "AttributedTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(AutoTypeBitfields) <= 8, - "AutoTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(BuiltinTypeBitfields) <= 8, - "BuiltinTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(FunctionTypeBitfields) <= 8, - "FunctionTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ObjCObjectTypeBitfields) <= 8, - "ObjCObjectTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(ReferenceTypeBitfields) <= 8, - "ReferenceTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(TypeWithKeywordBitfields) <= 8, - "TypeWithKeywordBitfields is larger than 8 bytes!"); - static_assert(sizeof(ElaboratedTypeBitfields) <= 8, - "ElaboratedTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(VectorTypeBitfields) <= 8, - "VectorTypeBitfields is larger than 8 bytes!"); - static_assert(sizeof(SubstTemplateTypeParmPackTypeBitfields) <= 8, - "SubstTemplateTypeParmPackTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(TemplateSpecializationTypeBitfields) <= 8, - "TemplateSpecializationTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(DependentTemplateSpecializationTypeBitfields) <= 8, - "DependentTemplateSpecializationTypeBitfields is larger" - " than 8 bytes!"); - static_assert(sizeof(PackExpansionTypeBitfields) <= 8, - "PackExpansionTypeBitfields is larger than 8 bytes"); }; private: @@ -1865,6 +1817,10 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { Type(TypeClass tc, QualType canon, TypeDependence Dependence) : ExtQualsTypeCommonBase(this, canon.isNull() ? QualType(this_(), 0) : canon) { + static_assert(sizeof(*this) <= 8 + sizeof(ExtQualsTypeCommonBase), + "changing bitfields changed sizeof(Type)!"); + static_assert(alignof(decltype(*this)) % sizeof(void *) == 0, + "Insufficient alignment!"); TypeBits.TC = tc; TypeBits.Dependence = static_cast(Dependence); TypeBits.CacheValid = false; @@ -3486,8 +3442,15 @@ class ConstantMatrixType final : public MatrixType { friend class ASTContext; /// The element type of the matrix. + // FIXME: Appears to be unused? There is also MatrixType::ElementType... QualType ElementType; + /// Number of rows and columns. + unsigned NumRows; + unsigned NumColumns; + + static constexpr unsigned MaxElementsPerDimension = (1 << 20) - 1; + ConstantMatrixType(QualType MatrixElementType, unsigned NRows, unsigned NColumns, QualType CanonElementType); @@ -3496,25 +3459,24 @@ class ConstantMatrixType final : public MatrixType { public: /// Returns the number of rows in the matrix. - unsigned getNumRows() const { return ConstantMatrixTypeBits.NumRows; } + unsigned getNumRows() const { return NumRows; } /// Returns the number of columns in the matrix. - unsigned getNumColumns() const { return ConstantMatrixTypeBits.NumColumns; } + unsigned getNumColumns() const { return NumColumns; } /// Returns the number of elements required to embed the matrix into a vector. unsigned getNumElementsFlattened() const { - return ConstantMatrixTypeBits.NumRows * ConstantMatrixTypeBits.NumColumns; + return getNumRows() * getNumColumns(); } /// Returns true if \p NumElements is a valid matrix dimension. - static bool isDimensionValid(uint64_t NumElements) { - return NumElements > 0 && - NumElements <= ConstantMatrixTypeBitfields::MaxElementsPerDimension; + static constexpr bool isDimensionValid(size_t NumElements) { + return NumElements > 0 && NumElements <= MaxElementsPerDimension; } /// Returns the maximum number of elements per dimension. - static unsigned getMaxElementsPerDimension() { - return ConstantMatrixTypeBitfields::MaxElementsPerDimension; + static constexpr unsigned getMaxElementsPerDimension() { + return MaxElementsPerDimension; } void Profile(llvm::FoldingSetNodeID &ID) { diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 4b04bfa0194ca..80b66e7702441 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -722,7 +722,8 @@ let Class = PackExpansionType in { } def : Creator<[{ - return ctx.getPackExpansionType(pattern, numExpansions); + return ctx.getPackExpansionType(pattern, numExpansions, + /*ExpectPackInType*/false); }]>; } diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index a207af5933731..252fbf0343227 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1108,6 +1108,7 @@ not made control-dependent on any additional values, e.g., unrolling a loop executed by all work items. Sample usage: + .. code-block:: c void convfunc(void) __attribute__((convergent)); @@ -3610,11 +3611,12 @@ distinguish USM (Unified Shared Memory) pointers that access global device memory from those that access global host memory. These new address spaces are a subset of the ``__global/opencl_global`` address space, the full address space set model for OpenCL 2.0 with the extension looks as follows: - generic->global->host - ->device - ->private - ->local - constant + + | generic->global->host + | ->device + | ->private + | ->local + | constant As ``global_device`` and ``global_host`` are a subset of ``__global/opencl_global`` address spaces it is allowed to convert diff --git a/clang/include/clang/Basic/BuiltinsBPF.def b/clang/include/clang/Basic/BuiltinsBPF.def index 237e9dc8784b4..04b45a52cbe71 100644 --- a/clang/include/clang/Basic/BuiltinsBPF.def +++ b/clang/include/clang/Basic/BuiltinsBPF.def @@ -23,5 +23,11 @@ TARGET_BUILTIN(__builtin_preserve_field_info, "Ui.", "t", "") // Get BTF type id. TARGET_BUILTIN(__builtin_btf_type_id, "Ui.", "t", "") +// Get type information. +TARGET_BUILTIN(__builtin_preserve_type_info, "Ui.", "t", "") + +// Preserve enum value. +TARGET_BUILTIN(__builtin_preserve_enum_value, "Li.", "t", "") + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def index d0f40f991a4c7..c0ac74686cf1c 100644 --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -66,67 +66,67 @@ TARGET_BUILTIN(__builtin_wasm_trunc_saturate_s_i64_f64, "LLid", "nc", "nontrappi TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i64_f64, "LLid", "nc", "nontrapping-fptoint") // SIMD builtins -TARGET_BUILTIN(__builtin_wasm_swizzle_v8x16, "V16cV16cV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_swizzle_v8x16, "V16ScV16ScV16Sc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_extract_lane_s_i8x16, "iV16cIi", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_extract_lane_u_i8x16, "iV16cIi", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_extract_lane_s_i8x16, "iV16ScIi", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_extract_lane_u_i8x16, "iV16UcIUi", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_extract_lane_s_i16x8, "iV8sIi", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_extract_lane_u_i16x8, "iV8sIi", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_extract_lane_u_i16x8, "iV8UsIUi", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_extract_lane_i32x4, "iV4iIi", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_extract_lane_i64x2, "LLiV2LLiIi", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_extract_lane_f32x4, "fV4fIi", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_extract_lane_f64x2, "dV2dIi", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_replace_lane_i8x16, "V16cV16cIii", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_replace_lane_i8x16, "V16ScV16ScIii", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_replace_lane_i16x8, "V8sV8sIii", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_replace_lane_i32x4, "V4iV4iIii", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_replace_lane_i64x2, "V2LLiV2LLiIiLLi", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_replace_lane_f32x4, "V4fV4fIif", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_replace_lane_f64x2, "V2dV2dIid", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_add_saturate_s_i8x16, "V16cV16cV16c", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_add_saturate_u_i8x16, "V16cV16cV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_add_saturate_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_add_saturate_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_add_saturate_s_i16x8, "V8sV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_add_saturate_u_i16x8, "V8sV8sV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_add_saturate_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_sub_saturate_s_i8x16, "V16cV16cV16c", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_sub_saturate_u_i8x16, "V16cV16cV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_sub_saturate_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_sub_saturate_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_sub_saturate_s_i16x8, "V8sV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_sub_saturate_u_i16x8, "V8sV8sV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_sub_saturate_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_abs_i8x16, "V16cV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_abs_i8x16, "V16ScV16Sc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_abs_i16x8, "V8sV8s", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_abs_i32x4, "V4iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_s_i8x16, "V16cV16cV16c", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_u_i8x16, "V16cV16cV16c", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_s_i8x16, "V16cV16cV16c", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_u_i8x16, "V16cV16cV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_min_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_min_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_max_s_i8x16, "V16ScV16ScV16Sc", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_max_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_min_s_i16x8, "V8sV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_u_i16x8, "V8sV8sV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_min_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_max_s_i16x8, "V8sV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_u_i16x8, "V8sV8sV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_max_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_min_s_i32x4, "V4iV4iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_min_u_i32x4, "V4iV4iV4i", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_min_u_i32x4, "V4UiV4UiV4Ui", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_max_s_i32x4, "V4iV4iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_max_u_i32x4, "V4iV4iV4i", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_max_u_i32x4, "V4UiV4UiV4Ui", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_avgr_u_i8x16, "V16cV16cV16c", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_avgr_u_i16x8, "V8sV8sV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_avgr_u_i8x16, "V16UcV16UcV16Uc", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_avgr_u_i16x8, "V8UsV8UsV8Us", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_bitselect, "V4iV4iV4iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_shuffle_v8x16, "V16cV16cV16cIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIi", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_shuffle_v8x16, "V16ScV16ScV16ScIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIi", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_any_true_i8x16, "iV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_any_true_i8x16, "iV16Sc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_any_true_i16x8, "iV8s", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_any_true_i32x4, "iV4i", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_any_true_i64x2, "iV2LLi", "nc", "unimplemented-simd128") -TARGET_BUILTIN(__builtin_wasm_all_true_i8x16, "iV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_all_true_i8x16, "iV16Sc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_all_true_i16x8, "iV8s", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_all_true_i32x4, "iV4i", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_all_true_i64x2, "iV2LLi", "nc", "unimplemented-simd128") -TARGET_BUILTIN(__builtin_wasm_bitmask_i8x16, "iV16c", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_bitmask_i8x16, "iV16Sc", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_bitmask_i16x8, "iV8s", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_bitmask_i32x4, "iV4i", "nc", "simd128") @@ -164,10 +164,13 @@ TARGET_BUILTIN(__builtin_wasm_qfms_f64x2, "V2dV2dV2dV2d", "nc", "unimplemented-s TARGET_BUILTIN(__builtin_wasm_trunc_saturate_s_i32x4_f32x4, "V4iV4f", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_trunc_saturate_u_i32x4_f32x4, "V4iV4f", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_narrow_s_i8x16_i16x8, "V16cV8sV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_narrow_u_i8x16_i16x8, "V16cV8sV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_narrow_s_i8x16_i16x8, "V16ScV8sV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_narrow_u_i8x16_i16x8, "V16UcV8UsV8Us", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_narrow_s_i16x8_i32x4, "V8sV4iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_narrow_u_i16x8_i32x4, "V8sV4iV4i", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_narrow_u_i16x8_i32x4, "V8UsV4UiV4Ui", "nc", "simd128") + +TARGET_BUILTIN(__builtin_wasm_load32_zero, "V4ii*", "nU", "simd128") +TARGET_BUILTIN(__builtin_wasm_load64_zero, "V2LLiLLi*", "nU", "simd128") #undef BUILTIN #undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 1716325a99312..19301e825bcfd 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -75,6 +75,7 @@ enum class CudaArch { GFX1011, GFX1012, GFX1030, + GFX1031, LAST, }; diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index b202d2abffa00..6434d92fd8fcf 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -270,8 +270,16 @@ def err_ifunc_resolver_return : Error< "ifunc resolver function must return a pointer">; def warn_atomic_op_misaligned : Warning< - "%select{large|misaligned}0 atomic operation may incur " - "significant performance penalty">, InGroup>; + "misaligned atomic operation may incur " + "significant performance penalty" + "; the expected alignment (%0 bytes) exceeds the actual alignment (%1 bytes)">, + InGroup; + +def warn_atomic_op_oversized : Warning< + "large atomic operation may incur " + "significant performance penalty" + "; the access size (%0 bytes) exceeds the max lock-free size (%1 bytes)">, +InGroup; def warn_alias_with_section : Warning< "%select{alias|ifunc}1 will not be in section '%0' but in the same section " diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 192a62b0035b4..a55227673b656 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -701,6 +701,7 @@ def ReorderInitList : DiagGroup<"reorder-init-list">; def Reorder : DiagGroup<"reorder", [ReorderCtor, ReorderInitList]>; def UndeclaredSelector : DiagGroup<"undeclared-selector">; def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">; +def AtomicAlignment : DiagGroup<"atomic-alignment">; def CustomAtomic : DiagGroup<"custom-atomic-properties">; def AtomicProperties : DiagGroup<"atomic-properties", [ImplicitAtomic, CustomAtomic]>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 07138795c06c0..12b732495f472 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10794,9 +10794,12 @@ def err_multiversion_duplicate : Error< "multiversioned function redeclarations require identical target attributes">; def err_multiversion_noproto : Error< "multiversioned function must have a prototype">; -def err_multiversion_no_other_attrs : Error< +def err_multiversion_disallowed_other_attr : Error< "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioning cannot be combined" - " with other attributes">; + " with attribute %1">; +def err_multiversion_mismatched_attrs + : Error<"attributes on multiversioned functions must all match, attribute " + "%0 %select{is missing|has different arguments}1">; def err_multiversion_diff : Error< "multiversioned function declaration has a different %select{calling convention" "|return type|constexpr specification|inline specification|storage class|" @@ -10905,6 +10908,14 @@ def err_preserve_field_info_not_const: Error< "__builtin_preserve_field_info argument %0 not a constant">; def err_btf_type_id_not_const: Error< "__builtin_btf_type_id argument %0 not a constant">; +def err_preserve_type_info_invalid : Error< + "__builtin_preserve_type_info argument %0 invalid">; +def err_preserve_type_info_not_const: Error< + "__builtin_preserve_type_info argument %0 not a constant">; +def err_preserve_enum_value_invalid : Error< + "__builtin_preserve_enum_value argument %0 invalid">; +def err_preserve_enum_value_not_const: Error< + "__builtin_preserve_enum_value argument %0 not a constant">; def err_bit_cast_non_trivially_copyable : Error< "__builtin_bit_cast %select{source|destination}0 type must be trivially copyable">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 03c1f03df2bb1..cbd7fe4f6c3df 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -397,7 +397,12 @@ def I_ : Flag<["-"], "I-">, Group, "remove current directory from include path">; def I : JoinedOrSeparate<["-"], "I">, Group, Flags<[CC1Option,CC1AsOption]>, MetaVarName<"">, - HelpText<"Add directory to include search path">; + HelpText<"Add directory to include search path. If there are multiple -I " + "options, these directories are searched in the order they are " + "given before the standard system directories are searched. " + "If the same directory is in the SYSTEM include search paths, for " + "example if also specified with -isystem, the -I option will be " + "ignored">; def L : JoinedOrSeparate<["-"], "L">, Flags<[RenderJoined]>, Group, MetaVarName<"">, HelpText<"Add directory to library search path">; def MD : Flag<["-"], "MD">, Group, @@ -691,6 +696,9 @@ def dependency_dot : Separate<["-"], "dependency-dot">, Flags<[CC1Option]>, HelpText<"Filename to write DOT-formatted header dependencies to">; def module_dependency_dir : Separate<["-"], "module-dependency-dir">, Flags<[CC1Option]>, HelpText<"Directory to dump module dependencies to">; +def dsym_dir : JoinedOrSeparate<["-"], "dsym-dir">, + Flags<[DriverOption, RenderAsInput]>, + HelpText<"Directory to output dSYM's (if any) to">, MetaVarName<"">; def dumpmachine : Flag<["-"], "dumpmachine">; def dumpspecs : Flag<["-"], "dumpspecs">, Flags<[Unsupported]>; def dumpversion : Flag<["-"], "dumpversion">; @@ -1263,7 +1271,7 @@ def finline_functions : Flag<["-"], "finline-functions">, Group, def finline_hint_functions: Flag<["-"], "finline-hint-functions">, Group, Flags<[CC1Option]>, HelpText<"Inline functions which are (explicitly or implicitly) marked inline">; def finline : Flag<["-"], "finline">, Group; -def fglobal_isel : Flag<["-"], "fglobal-isel">, Group, +def fglobal_isel : Flag<["-"], "fglobal-isel">, Group, HelpText<"Enables the global instruction selector">; def fexperimental_isel : Flag<["-"], "fexperimental-isel">, Group, Alias; @@ -1362,7 +1370,7 @@ def flto_EQ : Joined<["-"], "flto=">, Flags<[CoreOption, CC1Option]>, Group, Values<"thin,full">; def flto : Flag<["-"], "flto">, Flags<[CoreOption, CC1Option]>, Group, HelpText<"Enable LTO in 'full' mode">; -def fno_lto : Flag<["-"], "fno-lto">, Group, +def fno_lto : Flag<["-"], "fno-lto">, Flags<[CoreOption, CC1Option]>, Group, HelpText<"Disable LTO mode (default)">; def flto_jobs_EQ : Joined<["-"], "flto-jobs=">, Flags<[CC1Option]>, Group, diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 0a22b5af7c644..93a9126096557 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -2448,6 +2448,8 @@ class Declarator { /// \brief Sets a trailing requires clause for this declarator. void setTrailingRequiresClause(Expr *TRC) { TrailingRequiresClause = TRC; + + SetRangeEnd(TRC->getEndLoc()); } /// \brief Sets a trailing requires clause for this declarator. diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index cbd9254003282..a444843c50060 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1654,6 +1654,10 @@ def NoUncountedMemberChecker : Checker<"NoUncountedMemberChecker">, HelpText<"Check for no uncounted member variables.">, Documentation; +def UncountedLambdaCapturesChecker : Checker<"UncountedLambdaCapturesChecker">, + HelpText<"Check uncounted lambda captures.">, + Documentation; + } // end webkit let ParentPackage = WebKitAlpha in { diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 1abe297820886..a561ac67bf786 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -80,7 +80,7 @@ class SVal { #define ABSTRACT_SVAL_WITH_KIND(Id, Parent) Id ## Kind, #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.def" }; - enum { BaseBits = 2, BaseMask = 0x3 }; + enum { BaseBits = 2, BaseMask = 0b11 }; protected: const void *Data = nullptr; @@ -116,7 +116,7 @@ class SVal { unsigned getRawKind() const { return Kind; } BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } - unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } + unsigned getSubKind() const { return Kind >> BaseBits; } // This method is required for using SVal in a FoldingSetNode. It // extracts a unique signature for this SVal object. @@ -182,12 +182,6 @@ class SVal { /// should continue to the base regions if the region is not symbolic. SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const; - /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then - /// return that expression. Otherwise return NULL. - const SymExpr *getAsSymbolicExpression() const; - - const SymExpr *getAsSymExpr() const; - const MemRegion *getAsRegion() const; /// printJson - Pretty-prints in JSON format. diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h index d97b127638bba..8a873f9d5273b 100644 --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -267,66 +267,82 @@ class ParenExpression final : public Expression { syntax::Leaf *closeParen(); }; +/// Expression for literals. C++ [lex.literal] +class LiteralExpression : public Expression { +public: + LiteralExpression(NodeKind K) : Expression(K) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::IntegerLiteralExpression || + N->kind() == NodeKind::CharacterLiteralExpression || + N->kind() == NodeKind::FloatingLiteralExpression || + N->kind() == NodeKind::StringLiteralExpression || + N->kind() == NodeKind::BoolLiteralExpression || + N->kind() == NodeKind::CxxNullPtrExpression || + N->kind() == NodeKind::IntegerUserDefinedLiteralExpression || + N->kind() == NodeKind::FloatUserDefinedLiteralExpression || + N->kind() == NodeKind::CharUserDefinedLiteralExpression || + N->kind() == NodeKind::StringUserDefinedLiteralExpression; + } + syntax::Leaf *literalToken(); +}; + /// Expression for integer literals. C++ [lex.icon] -class IntegerLiteralExpression final : public Expression { +class IntegerLiteralExpression final : public LiteralExpression { public: - IntegerLiteralExpression() : Expression(NodeKind::IntegerLiteralExpression) {} + IntegerLiteralExpression() + : LiteralExpression(NodeKind::IntegerLiteralExpression) {} static bool classof(const Node *N) { return N->kind() == NodeKind::IntegerLiteralExpression; } - syntax::Leaf *literalToken(); }; /// Expression for character literals. C++ [lex.ccon] -class CharacterLiteralExpression final : public Expression { +class CharacterLiteralExpression final : public LiteralExpression { public: CharacterLiteralExpression() - : Expression(NodeKind::CharacterLiteralExpression) {} + : LiteralExpression(NodeKind::CharacterLiteralExpression) {} static bool classof(const Node *N) { return N->kind() == NodeKind::CharacterLiteralExpression; } - syntax::Leaf *literalToken(); }; /// Expression for floating-point literals. C++ [lex.fcon] -class FloatingLiteralExpression final : public Expression { +class FloatingLiteralExpression final : public LiteralExpression { public: FloatingLiteralExpression() - : Expression(NodeKind::FloatingLiteralExpression) {} + : LiteralExpression(NodeKind::FloatingLiteralExpression) {} static bool classof(const Node *N) { return N->kind() == NodeKind::FloatingLiteralExpression; } - syntax::Leaf *literalToken(); }; /// Expression for string-literals. C++ [lex.string] -class StringLiteralExpression final : public Expression { +class StringLiteralExpression final : public LiteralExpression { public: - StringLiteralExpression() : Expression(NodeKind::StringLiteralExpression) {} + StringLiteralExpression() + : LiteralExpression(NodeKind::StringLiteralExpression) {} static bool classof(const Node *N) { return N->kind() == NodeKind::StringLiteralExpression; } - syntax::Leaf *literalToken(); }; /// Expression for boolean literals. C++ [lex.bool] -class BoolLiteralExpression final : public Expression { +class BoolLiteralExpression final : public LiteralExpression { public: - BoolLiteralExpression() : Expression(NodeKind::BoolLiteralExpression) {} + BoolLiteralExpression() + : LiteralExpression(NodeKind::BoolLiteralExpression) {} static bool classof(const Node *N) { return N->kind() == NodeKind::BoolLiteralExpression; } - syntax::Leaf *literalToken(); }; /// Expression for the `nullptr` literal. C++ [lex.nullptr] -class CxxNullPtrExpression final : public Expression { +class CxxNullPtrExpression final : public LiteralExpression { public: - CxxNullPtrExpression() : Expression(NodeKind::CxxNullPtrExpression) {} + CxxNullPtrExpression() : LiteralExpression(NodeKind::CxxNullPtrExpression) {} static bool classof(const Node *N) { return N->kind() == NodeKind::CxxNullPtrExpression; } - syntax::Leaf *nullPtrKeyword(); }; /// Expression for user-defined literal. C++ [lex.ext] @@ -335,16 +351,15 @@ class CxxNullPtrExpression final : public Expression { /// user-defined-floating-point-literal /// user-defined-string-literal /// user-defined-character-literal -class UserDefinedLiteralExpression : public Expression { +class UserDefinedLiteralExpression : public LiteralExpression { public: - UserDefinedLiteralExpression(NodeKind K) : Expression(K) {} + UserDefinedLiteralExpression(NodeKind K) : LiteralExpression(K) {} static bool classof(const Node *N) { return N->kind() == NodeKind::IntegerUserDefinedLiteralExpression || N->kind() == NodeKind::FloatUserDefinedLiteralExpression || N->kind() == NodeKind::CharUserDefinedLiteralExpression || N->kind() == NodeKind::StringUserDefinedLiteralExpression; } - syntax::Leaf *literalToken(); }; /// Expression for user-defined-integer-literal. C++ [lex.ext] diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index ac63c88977eec..9760a09d098d5 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -10348,18 +10348,23 @@ static GVALinkage adjustGVALinkageForAttributes(const ASTContext &Context, } else if (D->hasAttr()) { if (L == GVA_DiscardableODR) return GVA_StrongODR; - } else if (Context.getLangOpts().CUDA && Context.getLangOpts().CUDAIsDevice && - D->hasAttr()) { + } else if (Context.getLangOpts().CUDA && Context.getLangOpts().CUDAIsDevice) { // Device-side functions with __global__ attribute must always be // visible externally so they can be launched from host. - if (L == GVA_DiscardableODR || L == GVA_Internal) + if (D->hasAttr() && + (L == GVA_DiscardableODR || L == GVA_Internal)) return GVA_StrongODR; + // Single source offloading languages like CUDA/HIP need to be able to + // access static device variables from host code of the same compilation + // unit. This is done by externalizing the static variable. + if (Context.shouldExternalizeStaticVar(D)) + return GVA_StrongExternal; } else if (Context.getLangOpts().SYCLIsDevice && D->hasAttr()) { if (L == GVA_DiscardableODR) return GVA_StrongODR; } - return L; + return L; } /// Adjust the GVALinkage for a declaration based on what an external AST source @@ -11226,3 +11231,11 @@ clang::operator<<(const DiagnosticBuilder &DB, return DB << Section.Decl; return DB << "a prior #pragma section"; } + +bool ASTContext::shouldExternalizeStaticVar(const Decl *D) const { + return !getLangOpts().GPURelocatableDeviceCode && + (D->hasAttr() || D->hasAttr()) && + isa(D) && cast(D)->isFileVarDecl() && + cast(D)->getStorageClass() == SC_Static && + CUDAStaticDeviceVarReferencedByHost.count(cast(D)); +} diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 05adf226bae37..99ce46e83123e 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -1560,11 +1560,11 @@ class TemplateDiff { if (!Tree.HasChildren()) { // If we're dealing with a template specialization with zero // arguments, there are no children; special-case this. - OS << FromTD->getNameAsString() << "<>"; + OS << FromTD->getDeclName() << "<>"; return; } - OS << FromTD->getNameAsString() << '<'; + OS << FromTD->getDeclName() << '<'; Tree.MoveToChild(); unsigned NumElideArgs = 0; bool AllArgsElided = true; @@ -1724,7 +1724,7 @@ class TemplateDiff { } if (Same) { - OS << "template " << FromTD->getNameAsString(); + OS << "template " << FromTD->getDeclName(); } else if (!PrintTree) { OS << (FromDefault ? "(default) template " : "template "); Bold(); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 256b8e8c8efbc..59fa8b0a2351c 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1504,7 +1504,8 @@ ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) { return ToPatternOrErr.takeError(); return Importer.getToContext().getPackExpansionType(*ToPatternOrErr, - T->getNumExpansions()); + T->getNumExpansions(), + /*ExpactPack=*/false); } ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType( diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 4351d9e76ac35..9b981bb00e776 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -528,7 +528,8 @@ void DeclPrinter::VisitEnumDecl(EnumDecl *D) { prettyPrintAttributes(D); - Out << ' ' << *D; + if (D->getDeclName()) + Out << ' ' << D->getDeclName(); if (Policy.SuppressDefinition) return; @@ -939,7 +940,12 @@ void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) { void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { if (D->isInline()) Out << "inline "; - Out << "namespace " << *D << " {\n"; + + Out << "namespace "; + if (D->getDeclName()) + Out << D->getDeclName() << ' '; + Out << "{\n"; + VisitDeclContext(D); Indent() << "}"; } @@ -1097,10 +1103,15 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { if (const TemplateTemplateParmDecl *TTP = dyn_cast(D)) { - Out << "class "; + Out << "class"; + if (TTP->isParameterPack()) - Out << "..."; - Out << D->getName(); + Out << " ..."; + else if (TTP->getDeclName()) + Out << ' '; + + if (TTP->getDeclName()) + Out << TTP->getDeclName(); } else if (auto *TD = D->getTemplatedDecl()) Visit(TD); else if (const auto *Concept = dyn_cast(D)) { @@ -1222,7 +1233,7 @@ void DeclPrinter::PrintObjCTypeParams(ObjCTypeParamList *Params) { break; } - Out << Param->getDeclName().getAsString(); + Out << Param->getDeclName(); if (Param->hasExplicitBound()) { Out << " : " << Param->getUnderlyingType().getAsString(Policy); @@ -1701,10 +1712,11 @@ void DeclPrinter::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP) { if (TTP->isParameterPack()) Out << " ..."; - else if (!TTP->getName().empty()) + else if (TTP->getDeclName()) Out << ' '; - Out << *TTP; + if (TTP->getDeclName()) + Out << TTP->getDeclName(); if (TTP->hasDefaultArgument() && !Policy.SuppressDefaultTemplateArguments) { Out << " = "; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp old mode 100755 new mode 100644 diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 293fdd4b3256e..c1c18f832d4fa 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -26,10 +26,10 @@ LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const { if (F) { if (auto *Cons = dyn_cast(F)) { - const std::string &Name = Cons->getParent()->getNameAsString(); + DeclarationName Name = Cons->getParent()->getDeclName(); OS << Name << "::" << Name << ":\n"; } else { - OS << F->getNameAsString() << ":\n"; + OS << F->getDeclName() << ":\n"; } } else { OS << "<>\n"; diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 5b6c6085e02cf..4aae63982542e 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -661,7 +661,7 @@ void TextNodeDumper::dumpBareDeclRef(const Decl *D) { void TextNodeDumper::dumpName(const NamedDecl *ND) { if (ND->getDeclName()) { ColorScope Color(OS, ShowColors, DeclNameColor); - OS << ' ' << ND->getNameAsString(); + OS << ' ' << ND->getDeclName(); } } @@ -1340,6 +1340,12 @@ void TextNodeDumper::VisitOMPIteratorExpr(const OMPIteratorExpr *Node) { } } +void TextNodeDumper::VisitConceptSpecializationExpr( + const ConceptSpecializationExpr *Node) { + OS << " "; + dumpBareDeclRef(Node->getFoundDecl()); +} + void TextNodeDumper::VisitRValueReferenceType(const ReferenceType *T) { if (T->isSpelledAsLValue()) OS << " written as lvalue reference"; @@ -1594,9 +1600,8 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { if (MD->size_overridden_methods() != 0) { auto dumpOverride = [=](const CXXMethodDecl *D) { SplitQualType T_split = D->getType().split(); - OS << D << " " << D->getParent()->getName() - << "::" << D->getNameAsString() << " '" - << QualType::getAsString(T_split, PrintPolicy) << "'"; + OS << D << " " << D->getParent()->getName() << "::" << D->getDeclName() + << " '" << QualType::getAsString(T_split, PrintPolicy) << "'"; }; AddChild([=] { @@ -2026,7 +2031,7 @@ void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) { OS << ' '; if (D->getQualifier()) D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); + OS << D->getDeclName(); } void TextNodeDumper::VisitUnresolvedUsingTypenameDecl( @@ -2034,7 +2039,7 @@ void TextNodeDumper::VisitUnresolvedUsingTypenameDecl( OS << ' '; if (D->getQualifier()) D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); + OS << D->getDeclName(); } void TextNodeDumper::VisitUnresolvedUsingValueDecl( @@ -2042,7 +2047,7 @@ void TextNodeDumper::VisitUnresolvedUsingValueDecl( OS << ' '; if (D->getQualifier()) D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); - OS << D->getNameAsString(); + OS << D->getDeclName(); dumpType(D->getType()); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 0dfe9c29c600e..e2cc227a099cc 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -308,10 +308,8 @@ ConstantMatrixType::ConstantMatrixType(QualType matrixType, unsigned nRows, ConstantMatrixType::ConstantMatrixType(TypeClass tc, QualType matrixType, unsigned nRows, unsigned nColumns, QualType canonType) - : MatrixType(tc, matrixType, canonType) { - ConstantMatrixTypeBits.NumRows = nRows; - ConstantMatrixTypeBits.NumColumns = nColumns; -} + : MatrixType(tc, matrixType, canonType), NumRows(nRows), + NumColumns(nColumns) {} DependentSizedMatrixType::DependentSizedMatrixType( const ASTContext &CTX, QualType ElementType, QualType CanonicalType, diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index fc74226951a4b..cde0bf448ecb2 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -4773,11 +4773,11 @@ CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E, CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors( BinaryOperator *E, bool ExternallyDestructed, TempDtorContext &Context) { if (E->isCommaOp()) { - // For comma operator LHS expression is visited - // before RHS expression. For destructors visit them in reverse order. - CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), ExternallyDestructed, Context); + // For the comma operator, the LHS expression is evaluated before the RHS + // expression, so prepend temporary destructors for the LHS first. CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context); - return LHSBlock ? LHSBlock : RHSBlock; + CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), ExternallyDestructed, Context); + return RHSBlock ? RHSBlock : LHSBlock; } if (E->isLogicalOp()) { @@ -4798,19 +4798,15 @@ CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors( } if (E->isAssignmentOp()) { - // For assignment operator (=) LHS expression is visited - // before RHS expression. For destructors visit them in reverse order. + // For assignment operators, the RHS expression is evaluated before the LHS + // expression, so prepend temporary destructors for the RHS first. CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context); CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context); return LHSBlock ? LHSBlock : RHSBlock; } - // For any other binary operator RHS expression is visited before - // LHS expression (order of children). For destructors visit them in reverse - // order. - CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context); - CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context); - return RHSBlock ? RHSBlock : LHSBlock; + // Any other operator is visited normally. + return VisitChildrenForTemporaryDtors(E, ExternallyDestructed, Context); } CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors( diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index 0b43e83221ae0..c2906dfe37656 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -173,6 +173,7 @@ bool AMDGPUTargetInfo::initFeatureMap( // XXX - What does the member GPU mean if device name string passed here? if (isAMDGCN(getTriple())) { switch (llvm::AMDGPU::parseArchAMDGCN(CPU)) { + case GK_GFX1031: case GK_GFX1030: Features["ci-insts"] = true; Features["dot1-insts"] = true; diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index e73ba3bed2635..b8d8e1b1ed0a4 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -204,6 +204,7 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case CudaArch::GFX1011: case CudaArch::GFX1012: case CudaArch::GFX1030: + case CudaArch::GFX1031: case CudaArch::LAST: break; case CudaArch::UNKNOWN: diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 543f232d24591..8b8f7d43b2773 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -159,11 +159,7 @@ void X86TargetInfo::setFeatureEnabled(llvm::StringMap &Features, } Features[Name] = Enabled; - - SmallVector ImpliedFeatures; - llvm::X86::getImpliedFeatures(Name, Enabled, ImpliedFeatures); - for (const auto &F : ImpliedFeatures) - Features[F] = Enabled; + llvm::X86::updateImpliedFeatures(Name, Enabled, Features); } /// handleTargetFeatures - Perform initialization based on the user diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index a58450ddd4c5f..b7ada4ac7e3bc 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -807,10 +807,20 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { bool Oversized = getContext().toBits(sizeChars) > MaxInlineWidthInBits; bool Misaligned = (Ptr.getAlignment() % sizeChars) != 0; bool UseLibcall = Misaligned | Oversized; + CharUnits MaxInlineWidth = + getContext().toCharUnitsFromBits(MaxInlineWidthInBits); - if (UseLibcall) { - CGM.getDiags().Report(E->getBeginLoc(), diag::warn_atomic_op_misaligned) - << !Oversized; + DiagnosticsEngine &Diags = CGM.getDiags(); + + if (Misaligned) { + Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_misaligned) + << (int)sizeChars.getQuantity() + << (int)Ptr.getAlignment().getQuantity(); + } + + if (Oversized) { + Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_oversized) + << (int)sizeChars.getQuantity() << (int)MaxInlineWidth.getQuantity(); } llvm::Value *Order = EmitScalarExpr(E->getOrder()); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 84c1e71487f4c..df08d50d71c0c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -10927,9 +10927,16 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { assert((BuiltinID == BPF::BI__builtin_preserve_field_info || - BuiltinID == BPF::BI__builtin_btf_type_id) && + BuiltinID == BPF::BI__builtin_btf_type_id || + BuiltinID == BPF::BI__builtin_preserve_type_info || + BuiltinID == BPF::BI__builtin_preserve_enum_value) && "unexpected BPF builtin"); + // A sequence number, injected into IR builtin functions, to + // prevent CSE given the only difference of the funciton + // may just be the debuginfo metadata. + static uint32_t BuiltinSeqNum; + switch (BuiltinID) { default: llvm_unreachable("Unexpected BPF builtin"); @@ -10960,65 +10967,65 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, {FieldAddr->getType()}); return Builder.CreateCall(FnGetFieldInfo, {FieldAddr, InfoKind}); } - case BPF::BI__builtin_btf_type_id: { - Value *FieldVal = nullptr; - - // The LValue cannot be converted Value in order to be used as the function - // parameter. If it is a structure, it is the "alloca" result of the LValue - // (a pointer) is used in the parameter. If it is a simple type, - // the value will be loaded from its corresponding "alloca" and used as - // the parameter. In our case, let us just get a pointer of the LValue - // since we do not really use the parameter. The purpose of parameter - // is to prevent the generated IR llvm.bpf.btf.type.id intrinsic call, - // which carries metadata, from being changed. - bool IsLValue = E->getArg(0)->isLValue(); - if (IsLValue) - FieldVal = EmitLValue(E->getArg(0)).getPointer(*this); - else - FieldVal = EmitScalarExpr(E->getArg(0)); + case BPF::BI__builtin_btf_type_id: + case BPF::BI__builtin_preserve_type_info: { + if (!getDebugInfo()) { + CGM.Error(E->getExprLoc(), "using builtin function without -g"); + return nullptr; + } + + const Expr *Arg0 = E->getArg(0); + llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateStandaloneType( + Arg0->getType(), Arg0->getExprLoc()); + ConstantInt *Flag = cast(EmitScalarExpr(E->getArg(1))); + Value *FlagValue = ConstantInt::get(Int64Ty, Flag->getSExtValue()); + Value *SeqNumVal = ConstantInt::get(Int32Ty, BuiltinSeqNum++); + + llvm::Function *FnDecl; + if (BuiltinID == BPF::BI__builtin_btf_type_id) + FnDecl = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::bpf_btf_type_id, {}); + else + FnDecl = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::bpf_preserve_type_info, {}); + CallInst *Fn = Builder.CreateCall(FnDecl, {SeqNumVal, FlagValue}); + Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo); + return Fn; + } + case BPF::BI__builtin_preserve_enum_value: { if (!getDebugInfo()) { - CGM.Error(E->getExprLoc(), "using __builtin_btf_type_id() without -g"); + CGM.Error(E->getExprLoc(), "using builtin function without -g"); return nullptr; } - // Generate debuginfo type for the first argument. - llvm::DIType *DbgInfo = - getDebugInfo()->getOrCreateStandaloneType(E->getArg(0)->getType(), - E->getArg(0)->getExprLoc()); + const Expr *Arg0 = E->getArg(0); + llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateStandaloneType( + Arg0->getType(), Arg0->getExprLoc()); + + // Find enumerator + const auto *UO = cast(Arg0->IgnoreParens()); + const auto *CE = cast(UO->getSubExpr()); + const auto *DR = cast(CE->getSubExpr()); + const auto *Enumerator = cast(DR->getDecl()); + + auto &InitVal = Enumerator->getInitVal(); + std::string InitValStr; + if (InitVal.isNegative() || InitVal > uint64_t(INT64_MAX)) + InitValStr = std::to_string(InitVal.getSExtValue()); + else + InitValStr = std::to_string(InitVal.getZExtValue()); + std::string EnumStr = Enumerator->getNameAsString() + ":" + InitValStr; + Value *EnumStrVal = Builder.CreateGlobalStringPtr(EnumStr); ConstantInt *Flag = cast(EmitScalarExpr(E->getArg(1))); Value *FlagValue = ConstantInt::get(Int64Ty, Flag->getSExtValue()); + Value *SeqNumVal = ConstantInt::get(Int32Ty, BuiltinSeqNum++); - // Built the IR for the btf_type_id intrinsic. - // - // In the above, we converted LValue argument to a pointer to LValue. - // For example, the following - // int v; - // C1: __builtin_btf_type_id(v, flag); - // will be converted to - // L1: llvm.bpf.btf.type.id(&v, flag) - // This makes it hard to differentiate from - // C2: __builtin_btf_type_id(&v, flag); - // to - // L2: llvm.bpf.btf.type.id(&v, flag) - // - // If both C1 and C2 are present in the code, the llvm may later - // on do CSE on L1 and L2, which will result in incorrect tagged types. - // - // The C1->L1 transformation only happens if the argument of - // __builtin_btf_type_id() is a LValue. So Let us put whether - // the argument is an LValue or not into generated IR. This should - // prevent potential CSE from causing debuginfo type loss. - // - // The generated IR intrinsics will hence look like - // L1: llvm.bpf.btf.type.id(&v, 1, flag) !di_type_for_{v}; - // L2: llvm.bpf.btf.type.id(&v, 0, flag) !di_type_for_{&v}; - Constant *CV = ConstantInt::get(IntTy, IsLValue); - llvm::Function *FnBtfTypeId = llvm::Intrinsic::getDeclaration( - &CGM.getModule(), llvm::Intrinsic::bpf_btf_type_id, - {FieldVal->getType(), CV->getType()}); - CallInst *Fn = Builder.CreateCall(FnBtfTypeId, {FieldVal, CV, FlagValue}); + llvm::Function *IntrinsicFn = llvm::Intrinsic::getDeclaration( + &CGM.getModule(), llvm::Intrinsic::bpf_preserve_enum_value, {}); + CallInst *Fn = + Builder.CreateCall(IntrinsicFn, {SeqNumVal, EnumStrVal, FlagValue}); Fn->setMetadata(LLVMContext::MD_preserve_access_index, DbgInfo); return Fn; } @@ -16503,6 +16510,16 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(IntNo, {ConvertType(E->getType()), Low->getType()}); return Builder.CreateCall(Callee, {Low, High}); } + case WebAssembly::BI__builtin_wasm_load32_zero: { + Value *Ptr = EmitScalarExpr(E->getArg(0)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_load32_zero); + return Builder.CreateCall(Callee, {Ptr}); + } + case WebAssembly::BI__builtin_wasm_load64_zero: { + Value *Ptr = EmitScalarExpr(E->getArg(0)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_load64_zero); + return Builder.CreateCall(Callee, {Ptr}); + } case WebAssembly::BI__builtin_wasm_shuffle_v8x16: { Value *Ops[18]; size_t OpIdx = 0; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 96abefd384f2c..4a29dbf7f8953 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -126,8 +126,13 @@ Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty, } void CodeGenFunction::InitTempAlloca(Address Var, llvm::Value *Init) { - assert(isa(Var.getPointer())); - auto *Store = new llvm::StoreInst(Init, Var.getPointer(), /*volatile*/ false, + auto *Alloca = Var.getPointer(); + assert(isa(Alloca) || + (isa(Alloca) && + isa( + cast(Alloca)->getPointerOperand()))); + + auto *Store = new llvm::StoreInst(Init, Alloca, /*volatile*/ false, Var.getAlignment().getAsAlign()); llvm::BasicBlock *Block = AllocaInsertPt->getParent(); Block->getInstList().insertAfter(AllocaInsertPt->getIterator(), Store); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index cd2b84f5dd203..26dfb6259a290 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -2250,8 +2250,7 @@ llvm::Value * CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { emitAutoreleasedReturnValueMarker(*this); llvm::CallInst::TailCallKind tailKind = - CGM.getTargetCodeGenInfo() - .shouldSuppressTailCallsOfRetainAutoreleasedReturnValue() + CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail() ? llvm::CallInst::TCK_NoTail : llvm::CallInst::TCK_None; return emitARCValueOperation( @@ -2270,9 +2269,14 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { llvm::Value * CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) { emitAutoreleasedReturnValueMarker(*this); - return emitARCValueOperation(*this, value, nullptr, - CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue, - llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue); + llvm::CallInst::TailCallKind tailKind = + CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail() + ? llvm::CallInst::TCK_NoTail + : llvm::CallInst::TCK_None; + return emitARCValueOperation( + *this, value, nullptr, + CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue, + llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue, tailKind); } /// Release the given object. diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 60c7081b135bf..547a9307dce2e 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -8826,6 +8826,30 @@ emitOffloadingArrays(CodeGenFunction &CGF, MapTypesArrayGbl->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); Info.MapTypesArray = MapTypesArrayGbl; + // If there's a present map type modifier, it must not be applied to the end + // of a region, so generate a separate map type array in that case. + if (Info.separateBeginEndCalls()) { + bool EndMapTypesDiffer = false; + for (uint64_t &Type : Mapping) { + if (Type & MappableExprsHandler::OMP_MAP_PRESENT) { + Type &= ~MappableExprsHandler::OMP_MAP_PRESENT; + EndMapTypesDiffer = true; + } + } + if (EndMapTypesDiffer) { + MapTypesArrayInit = + llvm::ConstantDataArray::get(CGF.Builder.getContext(), Mapping); + MaptypesName = CGM.getOpenMPRuntime().getName({"offload_maptypes"}); + MapTypesArrayGbl = new llvm::GlobalVariable( + CGM.getModule(), MapTypesArrayInit->getType(), + /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, + MapTypesArrayInit, MaptypesName); + MapTypesArrayGbl->setUnnamedAddr( + llvm::GlobalValue::UnnamedAddr::Global); + Info.MapTypesArrayEnd = MapTypesArrayGbl; + } + } + for (unsigned I = 0; I < Info.NumberOfPtrs; ++I) { llvm::Value *BPVal = *CombinedInfo.BasePointers[I]; llvm::Value *BP = CGF.Builder.CreateConstInBoundsGEP2_32( @@ -8878,12 +8902,16 @@ emitOffloadingArrays(CodeGenFunction &CGF, } /// Emit the arguments to be passed to the runtime library based on the -/// arrays of base pointers, pointers, sizes, map types, and mappers. +/// arrays of base pointers, pointers, sizes, map types, and mappers. If +/// ForEndCall, emit map types to be passed for the end of the region instead of +/// the beginning. static void emitOffloadingArraysArgument( CodeGenFunction &CGF, llvm::Value *&BasePointersArrayArg, llvm::Value *&PointersArrayArg, llvm::Value *&SizesArrayArg, llvm::Value *&MapTypesArrayArg, llvm::Value *&MappersArrayArg, - CGOpenMPRuntime::TargetDataInfo &Info) { + CGOpenMPRuntime::TargetDataInfo &Info, bool ForEndCall = false) { + assert((!ForEndCall || Info.separateBeginEndCalls()) && + "expected region end call to runtime only when end call is separate"); CodeGenModule &CGM = CGF.CGM; if (Info.NumberOfPtrs) { BasePointersArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32( @@ -8900,7 +8928,8 @@ static void emitOffloadingArraysArgument( /*Idx0=*/0, /*Idx1=*/0); MapTypesArrayArg = CGF.Builder.CreateConstInBoundsGEP2_32( llvm::ArrayType::get(CGM.Int64Ty, Info.NumberOfPtrs), - Info.MapTypesArray, + ForEndCall && Info.MapTypesArrayEnd ? Info.MapTypesArrayEnd + : Info.MapTypesArray, /*Idx0=*/0, /*Idx1=*/0); MappersArrayArg = @@ -10267,7 +10296,7 @@ void CGOpenMPRuntime::emitTargetDataCalls( llvm::Value *MappersArrayArg = nullptr; emitOffloadingArraysArgument(CGF, BasePointersArrayArg, PointersArrayArg, SizesArrayArg, MapTypesArrayArg, - MappersArrayArg, Info); + MappersArrayArg, Info, /*ForEndCall=*/false); // Emit device ID if any. llvm::Value *DeviceID = nullptr; @@ -10307,7 +10336,7 @@ void CGOpenMPRuntime::emitTargetDataCalls( llvm::Value *MappersArrayArg = nullptr; emitOffloadingArraysArgument(CGF, BasePointersArrayArg, PointersArrayArg, SizesArrayArg, MapTypesArrayArg, - MappersArrayArg, Info); + MappersArrayArg, Info, /*ForEndCall=*/true); // Emit device ID if any. llvm::Value *DeviceID = nullptr; diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index 0b91975343f70..1536181d67c55 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -1614,6 +1614,9 @@ class CGOpenMPRuntime { class TargetDataInfo { /// Set to true if device pointer information have to be obtained. bool RequiresDevicePointerInfo = false; + /// Set to true if Clang emits separate runtime calls for the beginning and + /// end of the region. These calls might have separate map type arrays. + bool SeparateBeginEndCalls = false; public: /// The array of base pointer passed to the runtime library. @@ -1622,8 +1625,14 @@ class CGOpenMPRuntime { llvm::Value *PointersArray = nullptr; /// The array of sizes passed to the runtime library. llvm::Value *SizesArray = nullptr; - /// The array of map types passed to the runtime library. + /// The array of map types passed to the runtime library for the beginning + /// of the region or for the entire region if there are no separate map + /// types for the region end. llvm::Value *MapTypesArray = nullptr; + /// The array of map types passed to the runtime library for the end of the + /// region, or nullptr if there are no separate map types for the region + /// end. + llvm::Value *MapTypesArrayEnd = nullptr; /// The array of user-defined mappers passed to the runtime library. llvm::Value *MappersArray = nullptr; /// Indicate whether any user-defined mapper exists. @@ -1635,14 +1644,17 @@ class CGOpenMPRuntime { llvm::DenseMap CaptureDeviceAddrMap; explicit TargetDataInfo() {} - explicit TargetDataInfo(bool RequiresDevicePointerInfo) - : RequiresDevicePointerInfo(RequiresDevicePointerInfo) {} + explicit TargetDataInfo(bool RequiresDevicePointerInfo, + bool SeparateBeginEndCalls) + : RequiresDevicePointerInfo(RequiresDevicePointerInfo), + SeparateBeginEndCalls(SeparateBeginEndCalls) {} /// Clear information about the data arrays. void clearArrayInfo() { BasePointersArray = nullptr; PointersArray = nullptr; SizesArray = nullptr; MapTypesArray = nullptr; + MapTypesArrayEnd = nullptr; MappersArray = nullptr; HasMapper = false; NumberOfPtrs = 0u; @@ -1653,6 +1665,7 @@ class CGOpenMPRuntime { MapTypesArray && (!HasMapper || MappersArray) && NumberOfPtrs; } bool requiresDevicePointerInfo() { return RequiresDevicePointerInfo; } + bool separateBeginEndCalls() { return SeparateBeginEndCalls; } }; /// Emit the target data mapping code associated with \a D. diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.cpp new file mode 100644 index 0000000000000..ccffdf43549fe --- /dev/null +++ b/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.cpp @@ -0,0 +1,61 @@ +//===-- CGOpenMPRuntimeAMDGCN.cpp - Interface to OpenMP AMDGCN Runtimes --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This provides a class for OpenMP runtime code generation specialized to +// AMDGCN targets from generalized CGOpenMPRuntimeGPU class. +// +//===----------------------------------------------------------------------===// + +#include "CGOpenMPRuntimeAMDGCN.h" +#include "CGOpenMPRuntimeGPU.h" +#include "CodeGenFunction.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclOpenMP.h" +#include "clang/AST/StmtOpenMP.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/Cuda.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/IR/IntrinsicsAMDGPU.h" + +using namespace clang; +using namespace CodeGen; +using namespace llvm::omp; + +CGOpenMPRuntimeAMDGCN::CGOpenMPRuntimeAMDGCN(CodeGenModule &CGM) + : CGOpenMPRuntimeGPU(CGM) { + if (!CGM.getLangOpts().OpenMPIsDevice) + llvm_unreachable("OpenMP AMDGCN can only handle device code."); +} + +llvm::Value *CGOpenMPRuntimeAMDGCN::getGPUWarpSize(CodeGenFunction &CGF) { + CGBuilderTy &Bld = CGF.Builder; + // return constant compile-time target-specific warp size + unsigned WarpSize = CGF.getTarget().getGridValue(llvm::omp::GV_Warp_Size); + return Bld.getInt32(WarpSize); +} + +llvm::Value *CGOpenMPRuntimeAMDGCN::getGPUThreadID(CodeGenFunction &CGF) { + CGBuilderTy &Bld = CGF.Builder; + llvm::Function *F = + CGF.CGM.getIntrinsic(llvm::Intrinsic::amdgcn_workitem_id_x); + return Bld.CreateCall(F, llvm::None, "nvptx_tid"); +} + +llvm::Value *CGOpenMPRuntimeAMDGCN::getGPUNumThreads(CodeGenFunction &CGF) { + CGBuilderTy &Bld = CGF.Builder; + llvm::Module *M = &CGF.CGM.getModule(); + const char *LocSize = "__ockl_get_local_size"; + llvm::Function *F = M->getFunction(LocSize); + if (!F) { + F = llvm::Function::Create( + llvm::FunctionType::get(CGF.Int64Ty, {CGF.Int32Ty}, false), + llvm::GlobalVariable::ExternalLinkage, LocSize, &CGF.CGM.getModule()); + } + return Bld.CreateTrunc( + Bld.CreateCall(F, {Bld.getInt32(0)}, "nvptx_num_threads"), CGF.Int32Ty); +} diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.h b/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.h new file mode 100644 index 0000000000000..c1421261bfc19 --- /dev/null +++ b/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.h @@ -0,0 +1,43 @@ +//===--- CGOpenMPRuntimeAMDGCN.h - Interface to OpenMP AMDGCN Runtimes ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This provides a class for OpenMP runtime code generation specialized to +// AMDGCN targets from generalized CGOpenMPRuntimeGPU class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMEAMDGCN_H +#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMEAMDGCN_H + +#include "CGOpenMPRuntime.h" +#include "CGOpenMPRuntimeGPU.h" +#include "CodeGenFunction.h" +#include "clang/AST/StmtOpenMP.h" + +namespace clang { +namespace CodeGen { + +class CGOpenMPRuntimeAMDGCN final : public CGOpenMPRuntimeGPU { + +public: + explicit CGOpenMPRuntimeAMDGCN(CodeGenModule &CGM); + + /// Get the GPU warp size. + llvm::Value *getGPUWarpSize(CodeGenFunction &CGF) override; + + /// Get the id of the current thread on the GPU. + llvm::Value *getGPUThreadID(CodeGenFunction &CGF) override; + + /// Get the maximum number of threads in a block of the GPU. + llvm::Value *getGPUNumThreads(CodeGenFunction &CGF) override; +}; + +} // namespace CodeGen +} // namespace clang + +#endif // LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMEAMDGCN_H diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 1cd89c540f478..9440758a85b6b 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // // This provides a generalized class for OpenMP runtime code generation -// specialized by GPU target NVPTX. +// specialized by GPU targets NVPTX and AMDGCN. // //===----------------------------------------------------------------------===// @@ -621,14 +621,6 @@ class CheckVarsEscapingDeclContext final }; } // anonymous namespace -/// Get the id of the current thread on the GPU. -static llvm::Value *getNVPTXThreadID(CodeGenFunction &CGF) { - return CGF.EmitRuntimeCall( - llvm::Intrinsic::getDeclaration( - &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_tid_x), - "nvptx_tid"); -} - /// Get the id of the warp in the block. /// We assume that the warp size is 32, which is always the case /// on the NVPTX device, to generate more efficient code. @@ -636,7 +628,8 @@ static llvm::Value *getNVPTXWarpID(CodeGenFunction &CGF) { CGBuilderTy &Bld = CGF.Builder; unsigned LaneIDBits = CGF.getTarget().getGridValue(llvm::omp::GV_Warp_Size_Log2); - return Bld.CreateAShr(getNVPTXThreadID(CGF), LaneIDBits, "nvptx_warp_id"); + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); + return Bld.CreateAShr(RT.getGPUThreadID(CGF), LaneIDBits, "nvptx_warp_id"); } /// Get the id of the current lane in the Warp. @@ -646,18 +639,11 @@ static llvm::Value *getNVPTXLaneID(CodeGenFunction &CGF) { CGBuilderTy &Bld = CGF.Builder; unsigned LaneIDMask = CGF.getContext().getTargetInfo().getGridValue( llvm::omp::GV_Warp_Size_Log2_Mask); - return Bld.CreateAnd(getNVPTXThreadID(CGF), Bld.getInt32(LaneIDMask), + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); + return Bld.CreateAnd(RT.getGPUThreadID(CGF), Bld.getInt32(LaneIDMask), "nvptx_lane_id"); } -/// Get the maximum number of threads in a block of the GPU. -static llvm::Value *getNVPTXNumThreads(CodeGenFunction &CGF) { - return CGF.EmitRuntimeCall( - llvm::Intrinsic::getDeclaration( - &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_ntid_x), - "nvptx_num_threads"); -} - /// Get the value of the thread_limit clause in the teams directive. /// For the 'generic' execution mode, the runtime encodes thread_limit in /// the launch parameters, always starting thread_limit+warpSize threads per @@ -668,9 +654,9 @@ static llvm::Value *getThreadLimit(CodeGenFunction &CGF, CGBuilderTy &Bld = CGF.Builder; auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); return IsInSPMDExecutionMode - ? getNVPTXNumThreads(CGF) - : Bld.CreateNUWSub(getNVPTXNumThreads(CGF), RT.getGPUWarpSize(CGF), - "thread_limit"); + ? RT.getGPUNumThreads(CGF) + : Bld.CreateNUWSub(RT.getGPUNumThreads(CGF), + RT.getGPUWarpSize(CGF), "thread_limit"); } /// Get the thread id of the OMP master thread. @@ -682,8 +668,8 @@ static llvm::Value *getThreadLimit(CodeGenFunction &CGF, /// If NumThreads is 1024, master id is 992. static llvm::Value *getMasterThreadID(CodeGenFunction &CGF) { CGBuilderTy &Bld = CGF.Builder; - llvm::Value *NumThreads = getNVPTXNumThreads(CGF); auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); + llvm::Value *NumThreads = RT.getGPUNumThreads(CGF); // We assume that the warp size is a power of 2. llvm::Value *Mask = Bld.CreateNUWSub(RT.getGPUWarpSize(CGF), Bld.getInt32(1)); @@ -1235,8 +1221,9 @@ void CGOpenMPRuntimeGPU::emitNonSPMDEntryHeader(CodeGenFunction &CGF, llvm::BasicBlock *MasterBB = CGF.createBasicBlock(".master"); EST.ExitBB = CGF.createBasicBlock(".exit"); + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); llvm::Value *IsWorker = - Bld.CreateICmpULT(getNVPTXThreadID(CGF), getThreadLimit(CGF)); + Bld.CreateICmpULT(RT.getGPUThreadID(CGF), getThreadLimit(CGF)); Bld.CreateCondBr(IsWorker, WorkerBB, MasterCheckBB); CGF.EmitBlock(WorkerBB); @@ -1245,7 +1232,7 @@ void CGOpenMPRuntimeGPU::emitNonSPMDEntryHeader(CodeGenFunction &CGF, CGF.EmitBlock(MasterCheckBB); llvm::Value *IsMaster = - Bld.CreateICmpEQ(getNVPTXThreadID(CGF), getMasterThreadID(CGF)); + Bld.CreateICmpEQ(RT.getGPUThreadID(CGF), getMasterThreadID(CGF)); Bld.CreateCondBr(IsMaster, MasterBB, EST.ExitBB); CGF.EmitBlock(MasterBB); @@ -2780,14 +2767,16 @@ void CGOpenMPRuntimeGPU::emitCriticalRegion( llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.critical.body"); llvm::BasicBlock *ExitBB = CGF.createBasicBlock("omp.critical.exit"); + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); + // Get the mask of active threads in the warp. llvm::Value *Mask = CGF.EmitRuntimeCall( createNVPTXRuntimeFunction(OMPRTL_NVPTX__kmpc_warp_active_thread_mask)); // Fetch team-local id of the thread. - llvm::Value *ThreadID = getNVPTXThreadID(CGF); + llvm::Value *ThreadID = RT.getGPUThreadID(CGF); // Get the width of the team. - llvm::Value *TeamWidth = getNVPTXNumThreads(CGF); + llvm::Value *TeamWidth = RT.getGPUNumThreads(CGF); // Initialize the counter variable for the loop. QualType Int32Ty = @@ -3250,8 +3239,9 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM, CGM.addCompilerUsedGlobal(TransferMedium); } + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); // Get the CUDA thread id of the current OpenMP thread on the GPU. - llvm::Value *ThreadID = getNVPTXThreadID(CGF); + llvm::Value *ThreadID = RT.getGPUThreadID(CGF); // nvptx_lane_id = nvptx_id % warpsize llvm::Value *LaneID = getNVPTXLaneID(CGF); // nvptx_warp_id = nvptx_id / warpsize @@ -4844,9 +4834,11 @@ void CGOpenMPRuntimeGPU::getDefaultDistScheduleAndChunk( CodeGenFunction &CGF, const OMPLoopDirective &S, OpenMPDistScheduleClauseKind &ScheduleKind, llvm::Value *&Chunk) const { + auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); if (getExecutionMode() == CGOpenMPRuntimeGPU::EM_SPMD) { ScheduleKind = OMPC_DIST_SCHEDULE_static; - Chunk = CGF.EmitScalarConversion(getNVPTXNumThreads(CGF), + Chunk = CGF.EmitScalarConversion( + RT.getGPUNumThreads(CGF), CGF.getContext().getIntTypeForBitwidth(32, /*Signed=*/0), S.getIterationVariable()->getType(), S.getBeginLoc()); return; @@ -5022,6 +5014,7 @@ void CGOpenMPRuntimeGPU::processRequiresDirective( case CudaArch::GFX1011: case CudaArch::GFX1012: case CudaArch::GFX1030: + case CudaArch::GFX1031: case CudaArch::UNKNOWN: break; case CudaArch::LAST: @@ -5082,6 +5075,7 @@ static std::pair getSMsBlocksPerSM(CodeGenModule &CGM) { case CudaArch::GFX1011: case CudaArch::GFX1012: case CudaArch::GFX1030: + case CudaArch::GFX1031: case CudaArch::UNKNOWN: break; case CudaArch::LAST: diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h index 316333072c5bc..7267511ca672a 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // // This provides a generalized class for OpenMP runtime code generation -// specialized by GPU target NVPTX. +// specialized by GPU targets NVPTX and AMDGCN. // //===----------------------------------------------------------------------===// @@ -199,9 +199,18 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime { void clear() override; /// Declare generalized virtual functions which need to be defined - /// by all specializations of OpenMPGPURuntime Targets. + /// by all specializations of OpenMPGPURuntime Targets like AMDGCN + /// and NVPTX. + + /// Get the GPU warp size. virtual llvm::Value *getGPUWarpSize(CodeGenFunction &CGF) = 0; + /// Get the id of the current thread on the GPU. + virtual llvm::Value *getGPUThreadID(CodeGenFunction &CGF) = 0; + + /// Get the maximum number of threads in a block of the GPU. + virtual llvm::Value *getGPUNumThreads(CodeGenFunction &CGF) = 0; + /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 /// global_tid, int proc_bind) to generate code for 'proc_bind' clause. virtual void emitProcBindClause(CodeGenFunction &CGF, diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp index 5fefc95ee4130..1688d07b90b6e 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -32,10 +32,25 @@ CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM) llvm_unreachable("OpenMP NVPTX can only handle device code."); } -/// Get the GPU warp size. llvm::Value *CGOpenMPRuntimeNVPTX::getGPUWarpSize(CodeGenFunction &CGF) { return CGF.EmitRuntimeCall( llvm::Intrinsic::getDeclaration( &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_warpsize), "nvptx_warp_size"); } + +llvm::Value *CGOpenMPRuntimeNVPTX::getGPUThreadID(CodeGenFunction &CGF) { + CGBuilderTy &Bld = CGF.Builder; + llvm::Function *F; + F = llvm::Intrinsic::getDeclaration( + &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_tid_x); + return Bld.CreateCall(F, llvm::None, "nvptx_tid"); +} + +llvm::Value *CGOpenMPRuntimeNVPTX::getGPUNumThreads(CodeGenFunction &CGF) { + CGBuilderTy &Bld = CGF.Builder; + llvm::Function *F; + F = llvm::Intrinsic::getDeclaration( + &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_ntid_x); + return Bld.CreateCall(F, llvm::None, "nvptx_num_threads"); +} diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h index 6dab79e6e20ae..5f16029592665 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h @@ -22,11 +22,19 @@ namespace clang { namespace CodeGen { -class CGOpenMPRuntimeNVPTX : public CGOpenMPRuntimeGPU { +class CGOpenMPRuntimeNVPTX final : public CGOpenMPRuntimeGPU { public: explicit CGOpenMPRuntimeNVPTX(CodeGenModule &CGM); + + /// Get the GPU warp size. llvm::Value *getGPUWarpSize(CodeGenFunction &CGF) override; + + /// Get the id of the current thread on the GPU. + llvm::Value *getGPUThreadID(CodeGenFunction &CGF) override; + + /// Get the maximum number of threads in a block of the GPU. + llvm::Value *getGPUNumThreads(CodeGenFunction &CGF) override; }; } // CodeGen namespace. diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index df1cc1666de4e..0bb57171db446 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -6039,7 +6039,8 @@ void CodeGenFunction::EmitOMPUseDeviceAddrClause( // Generate the instructions for '#pragma omp target data' directive. void CodeGenFunction::EmitOMPTargetDataDirective( const OMPTargetDataDirective &S) { - CGOpenMPRuntime::TargetDataInfo Info(/*RequiresDevicePointerInfo=*/true); + CGOpenMPRuntime::TargetDataInfo Info(/*RequiresDevicePointerInfo=*/true, + /*SeparateBeginEndCalls=*/true); // Create a pre/post action to signal the privatization of the device pointer. // This action can be replaced by the OpenMP runtime code generation to diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt index 92e6e15e94f18..0915f14e24a22 100644 --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -67,6 +67,7 @@ add_clang_library(clangCodeGen CGObjCRuntime.cpp CGOpenCLRuntime.cpp CGOpenMPRuntime.cpp + CGOpenMPRuntimeAMDGCN.cpp CGOpenMPRuntimeGPU.cpp CGOpenMPRuntimeNVPTX.cpp CGRecordLayoutBuilder.cpp diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c4ef7d42ecda1..f078d8ed09060 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -19,6 +19,7 @@ #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" #include "CGOpenMPRuntime.h" +#include "CGOpenMPRuntimeAMDGCN.h" #include "CGOpenMPRuntimeNVPTX.h" #include "CGSYCLRuntime.h" #include "CodeGenFunction.h" @@ -218,6 +219,11 @@ void CodeGenModule::createOpenMPRuntime() { "OpenMP NVPTX is only prepared to deal with device code."); OpenMPRuntime.reset(new CGOpenMPRuntimeNVPTX(*this)); break; + case llvm::Triple::amdgcn: + assert(getLangOpts().OpenMPIsDevice && + "OpenMP AMDGCN is only prepared to deal with device code."); + OpenMPRuntime.reset(new CGOpenMPRuntimeAMDGCN(*this)); + break; default: if (LangOpts.OpenMPSimd) OpenMPRuntime.reset(new CGOpenMPSIMDRuntime(*this)); diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 1861bf0591750..84daf3a5649e6 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -107,7 +107,8 @@ llvm::Type *CodeGenTypes::ConvertTypeForMem(QualType T, bool ForBitField) { // If this is a bool type, or an ExtIntType in a bitfield representation, // map this integer to the target-specified size. - if ((ForBitField && T->isExtIntType()) || R->isIntegerTy(1)) + if ((ForBitField && T->isExtIntType()) || + (!T->isExtIntType() && R->isIntegerTy(1))) return llvm::IntegerType::get(getLLVMContext(), (unsigned)Context.getTypeSize(T)); diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 8b5b4dd6e53ad..748f4be3eef93 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -2404,10 +2404,8 @@ class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { } /// Disable tail call on x86-64. The epilogue code before the tail jump blocks - /// the autoreleaseRV/retainRV optimization. - bool shouldSuppressTailCallsOfRetainAutoreleasedReturnValue() const override { - return true; - } + /// autoreleaseRV/retainRV and autoreleaseRV/unsafeClaimRV optimizations. + bool markARCOptimizedReturnCallsAsNoTail() const override { return true; } int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { return 7; @@ -10745,21 +10743,24 @@ class VEABIInfo : public DefaultABIInfo { } // end anonymous namespace ABIArgInfo VEABIInfo::classifyReturnType(QualType Ty) const { - if (Ty->isAnyComplexType()) { + if (Ty->isAnyComplexType()) return ABIArgInfo::getDirect(); - } + uint64_t Size = getContext().getTypeSize(Ty); + if (Size < 64 && Ty->isIntegerType()) + return ABIArgInfo::getExtend(Ty); return DefaultABIInfo::classifyReturnType(Ty); } ABIArgInfo VEABIInfo::classifyArgumentType(QualType Ty) const { - if (Ty->isAnyComplexType()) { + if (Ty->isAnyComplexType()) return ABIArgInfo::getDirect(); - } + uint64_t Size = getContext().getTypeSize(Ty); + if (Size < 64 && Ty->isIntegerType()) + return ABIArgInfo::getExtend(Ty); return DefaultABIInfo::classifyArgumentType(Ty); } void VEABIInfo::computeInfo(CGFunctionInfo &FI) const { - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &Arg : FI.arguments()) Arg.info = classifyArgumentType(Arg.type); diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 1152cabce4a0d..0df9667e91e16 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -163,11 +163,9 @@ class TargetCodeGenInfo { return ""; } - /// Determine whether a call to objc_retainAutoreleasedReturnValue should be - /// marked as 'notail'. - virtual bool shouldSuppressTailCallsOfRetainAutoreleasedReturnValue() const { - return false; - } + /// Determine whether a call to objc_retainAutoreleasedReturnValue or + /// objc_unsafeClaimAutoreleasedReturnValue should be marked as 'notail'. + virtual bool markARCOptimizedReturnCallsAsNoTail() const { return false; } /// Return a constant used by UBSan as a signature to identify functions /// possessing type information, or 0 if the platform is unsupported. diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index ca1696d1adbbd..c48f4bca8e05e 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -6110,10 +6110,20 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, } SmallString<128> BasePath(BaseInput); + SmallString<128> ExternalPath(""); StringRef BaseName; // Dsymutil actions should use the full path. - if (isa(JA) || isa(JA)) + if (isa(JA) && C.getArgs().hasArg(options::OPT_dsym_dir)) { + ExternalPath += C.getArgs().getLastArg(options::OPT_dsym_dir)->getValue(); + // We use posix style here because the tests (specifically + // darwin-dsymutil.c) demonstrate that posix style paths are acceptable + // even on Windows and if we don't then the similar test covering this + // fails. + llvm::sys::path::append(ExternalPath, llvm::sys::path::Style::posix, + llvm::sys::path::filename(BasePath)); + BaseName = ExternalPath; + } else if (isa(JA) || isa(JA)) BaseName = BasePath; else BaseName = llvm::sys::path::filename(BasePath); diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 09ae4538b3acc..7ca05a1f3a395 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -63,7 +63,7 @@ isExperimentalExtension(StringRef Ext) { Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc") return RISCVExtensionVersion{"0", "92"}; if (Ext == "v") - return RISCVExtensionVersion{"0", "8"}; + return RISCVExtensionVersion{"0", "9"}; return None; } diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 01780924fb06a..3fd0a5fb904d5 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -638,6 +638,16 @@ static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, return false; } +static const char *getAsNeededOption(const ToolChain &TC, bool as_needed) { + // While the Solaris 11.2 ld added --as-needed/--no-as-needed as aliases + // for the native forms -z ignore/-z record, they are missing in Illumos, + // so always use the native form. + if (TC.getTriple().isOSSolaris()) + return as_needed ? "-zignore" : "-zrecord"; + else + return as_needed ? "--as-needed" : "--no-as-needed"; +} + void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { // Fuchsia never needs these. Any sanitizer runtimes with system @@ -647,7 +657,7 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, // Force linking against the system libraries sanitizers depends on // (see PR15823 why this is necessary). - CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back(getAsNeededOption(TC, false)); // There's no libpthread or librt on RTEMS & Android. if (TC.getTriple().getOS() != llvm::Triple::RTEMS && !TC.getTriple().isAndroid()) { @@ -844,7 +854,7 @@ bool tools::addXRayRuntime(const ToolChain&TC, const ArgList &Args, ArgStringLis } void tools::linkXRayRuntimeDeps(const ToolChain &TC, ArgStringList &CmdArgs) { - CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back(getAsNeededOption(TC, false)); CmdArgs.push_back("-lpthread"); if (!TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lrt"); @@ -1269,7 +1279,7 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, bool AsNeeded = LGT == LibGccType::UnspecifiedLibGcc && !TC.getTriple().isAndroid() && !TC.getTriple().isOSCygMing(); if (AsNeeded) - CmdArgs.push_back("--as-needed"); + CmdArgs.push_back(getAsNeededOption(TC, true)); switch (UNW) { case ToolChain::UNW_None: @@ -1297,7 +1307,7 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, } if (AsNeeded) - CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back(getAsNeededOption(TC, false)); } static void AddLibgcc(const ToolChain &TC, const Driver &D, diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index ec0c628fe750d..d8f718306a45b 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -309,7 +309,8 @@ class LineJoiner { // Try to merge a control statement block with left brace wrapped if (I[1]->First->is(tok::l_brace) && (TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, - tok::kw_switch, tok::kw_try, tok::kw_do) || + tok::kw_switch, tok::kw_try, tok::kw_do, + TT_ForEachMacro) || (TheLine->First->is(tok::r_brace) && TheLine->First->Next && TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) && Style.BraceWrapping.AfterControlStatement == diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 6be0b193bcc9c..b74e04a5a7654 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1163,8 +1163,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections, OPT_compress_debug_sections_EQ)) { if (A->getOption().getID() == OPT_compress_debug_sections) { - // TODO: be more clever about the compression type auto-detection - Opts.setCompressDebugSections(llvm::DebugCompressionType::GNU); + Opts.setCompressDebugSections(llvm::DebugCompressionType::Z); } else { auto DCT = llvm::StringSwitch(A->getValue()) .Case("none", llvm::DebugCompressionType::None) diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 59a968b5c7099..92654dbe8a10a 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -121,7 +121,7 @@ class DeserializedDeclsChecker : public DelegatingDeserializationListener { = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0 was deserialized"); Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID) - << ND->getNameAsString(); + << ND; } DelegatingDeserializationListener::DeclRead(ID, D); diff --git a/clang/lib/Headers/__clang_cuda_math.h b/clang/lib/Headers/__clang_cuda_math.h index 332e616702acf..acb26ad345d59 100644 --- a/clang/lib/Headers/__clang_cuda_math.h +++ b/clang/lib/Headers/__clang_cuda_math.h @@ -195,8 +195,8 @@ __DEVICE__ int max(int __a, int __b) { return __nv_max(__a, __b); } __DEVICE__ int min(int __a, int __b) { return __nv_min(__a, __b); } __DEVICE__ double modf(double __a, double *__b) { return __nv_modf(__a, __b); } __DEVICE__ float modff(float __a, float *__b) { return __nv_modff(__a, __b); } -__DEVICE__ double nearbyint(double __a) { return __nv_nearbyint(__a); } -__DEVICE__ float nearbyintf(float __a) { return __nv_nearbyintf(__a); } +__DEVICE__ double nearbyint(double __a) { return __builtin_nearbyint(__a); } +__DEVICE__ float nearbyintf(float __a) { return __builtin_nearbyintf(__a); } __DEVICE__ double nextafter(double __a, double __b) { return __nv_nextafter(__a, __b); } @@ -249,8 +249,9 @@ __DEVICE__ double rhypot(double __a, double __b) { __DEVICE__ float rhypotf(float __a, float __b) { return __nv_rhypotf(__a, __b); } -__DEVICE__ double rint(double __a) { return __nv_rint(__a); } -__DEVICE__ float rintf(float __a) { return __nv_rintf(__a); } +// __nv_rint* in libdevice is buggy and produces incorrect results. +__DEVICE__ double rint(double __a) { return __builtin_rint(__a); } +__DEVICE__ float rintf(float __a) { return __builtin_rintf(__a); } __DEVICE__ double rnorm(int __a, const double *__b) { return __nv_rnorm(__a, __b); } diff --git a/clang/lib/Headers/altivec.h b/clang/lib/Headers/altivec.h index 4e25ec118072b..f42200f5bd4e7 100644 --- a/clang/lib/Headers/altivec.h +++ b/clang/lib/Headers/altivec.h @@ -16933,6 +16933,28 @@ vec_cnttzm(vector unsigned long long __a, vector unsigned long long __b) { return __builtin_altivec_vctzdm(__a, __b); } +/* vec_mod */ + +static __inline__ vector signed int __ATTRS_o_ai +vec_mod(vector signed int __a, vector signed int __b) { + return __a % __b; +} + +static __inline__ vector unsigned int __ATTRS_o_ai +vec_mod(vector unsigned int __a, vector unsigned int __b) { + return __a % __b; +} + +static __inline__ vector signed long long __ATTRS_o_ai +vec_mod(vector signed long long __a, vector signed long long __b) { + return __a % __b; +} + +static __inline__ vector unsigned long long __ATTRS_o_ai +vec_mod(vector unsigned long long __a, vector unsigned long long __b) { + return __a % __b; +} + /* vec_sldbi */ #define vec_sldb(__a, __b, __c) __builtin_altivec_vsldbi(__a, __b, (__c & 0x7)) diff --git a/clang/lib/Headers/wasm_simd128.h b/clang/lib/Headers/wasm_simd128.h index 967008b555f42..ac88516ac9248 100644 --- a/clang/lib/Headers/wasm_simd128.h +++ b/clang/lib/Headers/wasm_simd128.h @@ -18,8 +18,7 @@ typedef int32_t v128_t __attribute__((__vector_size__(16), __aligned__(16))); // Internal types determined by clang builtin definitions typedef int32_t __v128_u __attribute__((__vector_size__(16), __aligned__(1))); -typedef char __i8x16 __attribute__((__vector_size__(16), __aligned__(16))); -typedef signed char __s8x16 +typedef signed char __i8x16 __attribute__((__vector_size__(16), __aligned__(16))); typedef unsigned char __u8x16 __attribute__((__vector_size__(16), __aligned__(16))); @@ -280,7 +279,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_splat(int8_t __a) { (__builtin_wasm_extract_lane_s_i8x16((__i8x16)(__a), __i)) #define wasm_u8x16_extract_lane(__a, __i) \ - (__builtin_wasm_extract_lane_u_i8x16((__i8x16)(__a), __i)) + (__builtin_wasm_extract_lane_u_i8x16((__u8x16)(__a), __i)) #define wasm_i8x16_replace_lane(__a, __i, __b) \ ((v128_t)__builtin_wasm_replace_lane_i8x16((__i8x16)(__a), __i, __b)) @@ -293,7 +292,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_splat(int16_t __a) { (__builtin_wasm_extract_lane_s_i16x8((__i16x8)(__a), __i)) #define wasm_u16x8_extract_lane(__a, __i) \ - (__builtin_wasm_extract_lane_u_i16x8((__i16x8)(__a), __i)) + (__builtin_wasm_extract_lane_u_i16x8((__u16x8)(__a), __i)) #define wasm_i16x8_replace_lane(__a, __i, __b) \ ((v128_t)__builtin_wasm_replace_lane_i16x8((__i16x8)(__a), __i, __b)) @@ -340,17 +339,17 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_splat(double __a) { static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_eq(v128_t __a, v128_t __b) { - return (v128_t)((__s8x16)__a == (__s8x16)__b); + return (v128_t)((__i8x16)__a == (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_ne(v128_t __a, v128_t __b) { - return (v128_t)((__s8x16)__a != (__s8x16)__b); + return (v128_t)((__i8x16)__a != (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_lt(v128_t __a, v128_t __b) { - return (v128_t)((__s8x16)__a < (__s8x16)__b); + return (v128_t)((__i8x16)__a < (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_lt(v128_t __a, @@ -360,7 +359,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_lt(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_gt(v128_t __a, v128_t __b) { - return (v128_t)((__s8x16)__a > (__s8x16)__b); + return (v128_t)((__i8x16)__a > (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_gt(v128_t __a, @@ -370,7 +369,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_gt(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_le(v128_t __a, v128_t __b) { - return (v128_t)((__s8x16)__a <= (__s8x16)__b); + return (v128_t)((__i8x16)__a <= (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_le(v128_t __a, @@ -380,7 +379,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_le(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_ge(v128_t __a, v128_t __b) { - return (v128_t)((__s8x16)__a >= (__s8x16)__b); + return (v128_t)((__i8x16)__a >= (__i8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_ge(v128_t __a, @@ -602,7 +601,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_shl(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_shr(v128_t __a, int32_t __b) { - return (v128_t)((__s8x16)__a >> __b); + return (v128_t)((__i8x16)__a >> __b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_shr(v128_t __a, @@ -623,8 +622,8 @@ wasm_i8x16_add_saturate(v128_t __a, v128_t __b) { static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_add_saturate(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_add_saturate_u_i8x16((__i8x16)__a, - (__i8x16)__b); + return (v128_t)__builtin_wasm_add_saturate_u_i8x16((__u8x16)__a, + (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_sub(v128_t __a, @@ -640,8 +639,8 @@ wasm_i8x16_sub_saturate(v128_t __a, v128_t __b) { static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_sub_saturate(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_sub_saturate_u_i8x16((__i8x16)__a, - (__i8x16)__b); + return (v128_t)__builtin_wasm_sub_saturate_u_i8x16((__u8x16)__a, + (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_min(v128_t __a, @@ -651,7 +650,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_min(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_u_i8x16((__i8x16)__a, (__i8x16)__b); + return (v128_t)__builtin_wasm_min_u_i8x16((__u8x16)__a, (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_max(v128_t __a, @@ -661,12 +660,12 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_max(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_u_i8x16((__i8x16)__a, (__i8x16)__b); + return (v128_t)__builtin_wasm_max_u_i8x16((__u8x16)__a, (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_avgr(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_avgr_u_i8x16((__i8x16)__a, (__i8x16)__b); + return (v128_t)__builtin_wasm_avgr_u_i8x16((__u8x16)__a, (__u8x16)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_abs(v128_t __a) { @@ -713,8 +712,8 @@ wasm_i16x8_add_saturate(v128_t __a, v128_t __b) { static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_add_saturate(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_add_saturate_u_i16x8((__i16x8)__a, - (__i16x8)__b); + return (v128_t)__builtin_wasm_add_saturate_u_i16x8((__u16x8)__a, + (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_sub(v128_t __a, @@ -730,8 +729,8 @@ wasm_i16x8_sub_saturate(v128_t __a, v128_t __b) { static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_sub_saturate(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_sub_saturate_u_i16x8((__i16x8)__a, - (__i16x8)__b); + return (v128_t)__builtin_wasm_sub_saturate_u_i16x8((__u16x8)__a, + (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_mul(v128_t __a, @@ -746,7 +745,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_min(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_u_i16x8((__i16x8)__a, (__i16x8)__b); + return (v128_t)__builtin_wasm_min_u_i16x8((__u16x8)__a, (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_max(v128_t __a, @@ -756,12 +755,12 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_max(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_u_i16x8((__i16x8)__a, (__i16x8)__b); + return (v128_t)__builtin_wasm_max_u_i16x8((__u16x8)__a, (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_avgr(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_avgr_u_i16x8((__i16x8)__a, (__i16x8)__b); + return (v128_t)__builtin_wasm_avgr_u_i16x8((__u16x8)__a, (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_abs(v128_t __a) { @@ -817,7 +816,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_min(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_min(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_min_u_i32x4((__i32x4)__a, (__i32x4)__b); + return (v128_t)__builtin_wasm_min_u_i32x4((__u32x4)__a, (__u32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_max(v128_t __a, @@ -827,7 +826,7 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_max(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_max(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_max_u_i32x4((__i32x4)__a, (__i32x4)__b); + return (v128_t)__builtin_wasm_max_u_i32x4((__u32x4)__a, (__u32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_neg(v128_t __a) { @@ -1078,8 +1077,8 @@ wasm_i8x16_narrow_i16x8(v128_t __a, v128_t __b) { static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_narrow_i16x8(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_narrow_u_i8x16_i16x8((__i16x8)__a, - (__i16x8)__b); + return (v128_t)__builtin_wasm_narrow_u_i8x16_i16x8((__u16x8)__a, + (__u16x8)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS @@ -1090,8 +1089,8 @@ wasm_i16x8_narrow_i32x4(v128_t __a, v128_t __b) { static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_narrow_i32x4(v128_t __a, v128_t __b) { - return (v128_t)__builtin_wasm_narrow_u_i16x8_i32x4((__i32x4)__a, - (__i32x4)__b); + return (v128_t)__builtin_wasm_narrow_u_i16x8_i32x4((__u32x4)__a, + (__u32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS diff --git a/clang/lib/Index/FileIndexRecord.cpp b/clang/lib/Index/FileIndexRecord.cpp index 753bdf2ce21d7..df18a9aed8b79 100644 --- a/clang/lib/Index/FileIndexRecord.cpp +++ b/clang/lib/Index/FileIndexRecord.cpp @@ -52,7 +52,7 @@ void FileIndexRecord::print(llvm::raw_ostream &OS) const { << ':' << PLoc.getColumn(); if (auto ND = dyn_cast(D)) { - OS << ' ' << ND->getNameAsString(); + OS << ' ' << ND->getDeclName(); } OS << '\n'; diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 8a92a8259c444..f24cb3d3f0b7d 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3191,7 +3191,6 @@ static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) { /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. -/// \param RLoc Returned location of right paren. ExprResult Parser::ParseOpenMPIteratorsExpr() { assert(Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator" && "Expected 'iterator' token."); diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 3b73568938337..5cc215e08ea83 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1849,8 +1849,8 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { << *PossibleMatch); if (Verbose && POK == POK_VarAccess) { PartialDiagnosticAt VNote(D->getLocation(), - S.PDiag(diag::note_guarded_by_declared_here) - << D->getNameAsString()); + S.PDiag(diag::note_guarded_by_declared_here) + << D->getDeclName()); Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote)); } else Warnings.emplace_back(std::move(Warning), getNotes(Note)); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 14da704ad3e17..7f6e1bec8f234 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2582,52 +2582,151 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) { + if (Arg->getType()->getAsPlaceholderType()) + return false; + + // The first argument needs to be a record field access. + // If it is an array element access, we delay decision + // to BPF backend to check whether the access is a + // field access or not. + return (Arg->IgnoreParens()->getObjectKind() == OK_BitField || + dyn_cast(Arg->IgnoreParens()) || + dyn_cast(Arg->IgnoreParens())); +} + +static bool isValidBPFPreserveTypeInfoArg(Expr *Arg) { + QualType ArgType = Arg->getType(); + if (ArgType->getAsPlaceholderType()) + return false; + + // for TYPE_EXISTENCE/TYPE_SIZEOF reloc type + // format: + // 1. __builtin_preserve_type_info(*( *)0, flag); + // 2. var; + // __builtin_preserve_type_info(var, flag); + if (!dyn_cast(Arg->IgnoreParens()) && + !dyn_cast(Arg->IgnoreParens())) + return false; + + // Typedef type. + if (ArgType->getAs()) + return true; + + // Record type or Enum type. + const Type *Ty = ArgType->getUnqualifiedDesugaredType(); + if (const auto *RT = Ty->getAs()) { + if (!RT->getDecl()->getDeclName().isEmpty()) + return true; + } else if (const auto *ET = Ty->getAs()) { + if (!ET->getDecl()->getDeclName().isEmpty()) + return true; + } + + return false; +} + +static bool isValidBPFPreserveEnumValueArg(Expr *Arg) { + QualType ArgType = Arg->getType(); + if (ArgType->getAsPlaceholderType()) + return false; + + // for ENUM_VALUE_EXISTENCE/ENUM_VALUE reloc type + // format: + // __builtin_preserve_enum_value(*( *), + // flag); + const auto *UO = dyn_cast(Arg->IgnoreParens()); + if (!UO) + return false; + + const auto *CE = dyn_cast(UO->getSubExpr()); + if (!CE || CE->getCastKind() != CK_IntegralToPointer) + return false; + + // The integer must be from an EnumConstantDecl. + const auto *DR = dyn_cast(CE->getSubExpr()); + if (!DR) + return false; + + const EnumConstantDecl *Enumerator = + dyn_cast(DR->getDecl()); + if (!Enumerator) + return false; + + // The type must be EnumType. + const Type *Ty = ArgType->getUnqualifiedDesugaredType(); + const auto *ET = Ty->getAs(); + if (!ET) + return false; + + // The enum value must be supported. + for (auto *EDI : ET->getDecl()->enumerators()) { + if (EDI == Enumerator) + return true; + } + + return false; +} + bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { assert((BuiltinID == BPF::BI__builtin_preserve_field_info || - BuiltinID == BPF::BI__builtin_btf_type_id) && - "unexpected ARM builtin"); + BuiltinID == BPF::BI__builtin_btf_type_id || + BuiltinID == BPF::BI__builtin_preserve_type_info || + BuiltinID == BPF::BI__builtin_preserve_enum_value) && + "unexpected BPF builtin"); if (checkArgCount(*this, TheCall, 2)) return true; - Expr *Arg; - if (BuiltinID == BPF::BI__builtin_btf_type_id) { - // The second argument needs to be a constant int - Arg = TheCall->getArg(1); - if (!Arg->isIntegerConstantExpr(Context)) { - Diag(Arg->getBeginLoc(), diag::err_btf_type_id_not_const) - << 2 << Arg->getSourceRange(); - return true; - } - - TheCall->setType(Context.UnsignedIntTy); - return false; + // The second argument needs to be a constant int + Expr *Arg = TheCall->getArg(1); + Optional Value = Arg->getIntegerConstantExpr(Context); + diag::kind kind; + if (!Value) { + if (BuiltinID == BPF::BI__builtin_preserve_field_info) + kind = diag::err_preserve_field_info_not_const; + else if (BuiltinID == BPF::BI__builtin_btf_type_id) + kind = diag::err_btf_type_id_not_const; + else if (BuiltinID == BPF::BI__builtin_preserve_type_info) + kind = diag::err_preserve_type_info_not_const; + else + kind = diag::err_preserve_enum_value_not_const; + Diag(Arg->getBeginLoc(), kind) << 2 << Arg->getSourceRange(); + return true; } - // The first argument needs to be a record field access. - // If it is an array element access, we delay decision - // to BPF backend to check whether the access is a - // field access or not. + // The first argument Arg = TheCall->getArg(0); - if (Arg->getType()->getAsPlaceholderType() || - (Arg->IgnoreParens()->getObjectKind() != OK_BitField && - !dyn_cast(Arg->IgnoreParens()) && - !dyn_cast(Arg->IgnoreParens()))) { - Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_field) - << 1 << Arg->getSourceRange(); - return true; + bool InvalidArg = false; + bool ReturnUnsignedInt = true; + if (BuiltinID == BPF::BI__builtin_preserve_field_info) { + if (!isValidBPFPreserveFieldInfoArg(Arg)) { + InvalidArg = true; + kind = diag::err_preserve_field_info_not_field; + } + } else if (BuiltinID == BPF::BI__builtin_preserve_type_info) { + if (!isValidBPFPreserveTypeInfoArg(Arg)) { + InvalidArg = true; + kind = diag::err_preserve_type_info_invalid; + } + } else if (BuiltinID == BPF::BI__builtin_preserve_enum_value) { + if (!isValidBPFPreserveEnumValueArg(Arg)) { + InvalidArg = true; + kind = diag::err_preserve_enum_value_invalid; + } + ReturnUnsignedInt = false; } - // The second argument needs to be a constant int - Arg = TheCall->getArg(1); - if (!Arg->isIntegerConstantExpr(Context)) { - Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const) - << 2 << Arg->getSourceRange(); + if (InvalidArg) { + Diag(Arg->getBeginLoc(), kind) << 1 << Arg->getSourceRange(); return true; } - TheCall->setType(Context.UnsignedIntTy); + if (ReturnUnsignedInt) + TheCall->setType(Context.UnsignedIntTy); + else + TheCall->setType(Context.UnsignedLongTy); return false; } @@ -11064,7 +11163,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, BitfieldEnumDecl->getNumPositiveBits() > 0 && BitfieldEnumDecl->getNumNegativeBits() == 0) { S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield) - << BitfieldEnumDecl->getNameAsString(); + << BitfieldEnumDecl; } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d322e6dbe4438..1a28a63bdf0f7 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10031,31 +10031,50 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) { // multiversion functions. static bool AttrCompatibleWithMultiVersion(attr::Kind Kind, MultiVersionKind MVType) { + // Note: this list/diagnosis must match the list in + // checkMultiversionAttributesAllSame. switch (Kind) { default: return false; case attr::Used: return MVType == MultiVersionKind::Target; + case attr::NonNull: + case attr::NoThrow: + return true; } } -static bool HasNonMultiVersionAttributes(const FunctionDecl *FD, - MultiVersionKind MVType) { +static bool checkNonMultiVersionCompatAttributes(Sema &S, + const FunctionDecl *FD, + const FunctionDecl *CausedFD, + MultiVersionKind MVType) { + bool IsCPUSpecificCPUDispatchMVType = + MVType == MultiVersionKind::CPUDispatch || + MVType == MultiVersionKind::CPUSpecific; + const auto Diagnose = [FD, CausedFD, IsCPUSpecificCPUDispatchMVType]( + Sema &S, const Attr *A) { + S.Diag(FD->getLocation(), diag::err_multiversion_disallowed_other_attr) + << IsCPUSpecificCPUDispatchMVType << A; + if (CausedFD) + S.Diag(CausedFD->getLocation(), diag::note_multiversioning_caused_here); + return true; + }; + for (const Attr *A : FD->attrs()) { switch (A->getKind()) { case attr::CPUDispatch: case attr::CPUSpecific: if (MVType != MultiVersionKind::CPUDispatch && MVType != MultiVersionKind::CPUSpecific) - return true; + return Diagnose(S, A); break; case attr::Target: if (MVType != MultiVersionKind::Target) - return true; + return Diagnose(S, A); break; default: if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType)) - return true; + return Diagnose(S, A); break; } } @@ -10189,18 +10208,12 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, MVType == MultiVersionKind::CPUDispatch || MVType == MultiVersionKind::CPUSpecific; - // For now, disallow all other attributes. These should be opt-in, but - // an analysis of all of them is a future FIXME. - if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) { - S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs) - << IsCPUSpecificCPUDispatchMVType; - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + if (CausesMV && OldFD && + checkNonMultiVersionCompatAttributes(S, OldFD, NewFD, MVType)) return true; - } - if (HasNonMultiVersionAttributes(NewFD, MVType)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs) - << IsCPUSpecificCPUDispatchMVType; + if (checkNonMultiVersionCompatAttributes(S, NewFD, nullptr, MVType)) + return true; // Only allow transition to MultiVersion if it hasn't been used. if (OldFD && CausesMV && OldFD->isUsed(false)) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 532e7d5b9cdc2..7e66d9ab0e3e9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17891,6 +17891,25 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, if (Var->isInvalidDecl()) return; + // Record a CUDA/HIP static device/constant variable if it is referenced + // by host code. This is done conservatively, when the variable is referenced + // in any of the following contexts: + // - a non-function context + // - a host function + // - a host device function + // This also requires the reference of the static device/constant variable by + // host code to be visible in the device compilation for the compiler to be + // able to externalize the static device/constant variable. + if ((Var->hasAttr() || Var->hasAttr()) && + Var->isFileVarDecl() && Var->getStorageClass() == SC_Static) { + auto *CurContext = SemaRef.CurContext; + if (!CurContext || !isa(CurContext) || + cast(CurContext)->hasAttr() || + (!cast(CurContext)->hasAttr() && + !cast(CurContext)->hasAttr())) + SemaRef.getASTContext().CUDAStaticDeviceVarReferencedByHost.insert(Var); + } + auto *MSI = Var->getMemberSpecializationInfo(); TemplateSpecializationKind TSK = MSI ? MSI->getTemplateSpecializationKind() : Var->getTemplateSpecializationKind(); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 1f7d0f0e8d973..7aa94502fa846 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1201,6 +1201,120 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { return false; } +/// Attempt to deduce the template arguments by checking the base types +/// according to (C++20 [temp.deduct.call] p4b3. +/// +/// \param S the semantic analysis object within which we are deducing. +/// +/// \param RecordT the top level record object we are deducing against. +/// +/// \param TemplateParams the template parameters that we are deducing. +/// +/// \param SpecParam the template specialization parameter type. +/// +/// \param Info information about the template argument deduction itself. +/// +/// \param Deduced the deduced template arguments. +/// +/// \returns the result of template argument deduction with the bases. "invalid" +/// means no matches, "success" found a single item, and the +/// "MiscellaneousDeductionFailure" result happens when the match is ambiguous. +static Sema::TemplateDeductionResult DeduceTemplateBases( + Sema &S, const RecordType *RecordT, TemplateParameterList *TemplateParams, + const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { + // C++14 [temp.deduct.call] p4b3: + // If P is a class and P has the form simple-template-id, then the + // transformed A can be a derived class of the deduced A. Likewise if + // P is a pointer to a class of the form simple-template-id, the + // transformed A can be a pointer to a derived class pointed to by the + // deduced A. However, if there is a class C that is a (direct or + // indirect) base class of D and derived (directly or indirectly) from a + // class B and that would be a valid deduced A, the deduced A cannot be + // B or pointer to B, respectively. + // + // These alternatives are considered only if type deduction would + // otherwise fail. If they yield more than one possible deduced A, the + // type deduction fails. + + // Use a breadth-first search through the bases to collect the set of + // successful matches. Visited contains the set of nodes we have already + // visited, while ToVisit is our stack of records that we still need to + // visit. Matches contains a list of matches that have yet to be + // disqualified. + llvm::SmallPtrSet Visited; + SmallVector ToVisit; + // We iterate over this later, so we have to use MapVector to ensure + // determinism. + llvm::MapVector> + Matches; + + auto AddBases = [&Visited, &ToVisit](const RecordType *RT) { + CXXRecordDecl *RD = cast(RT->getDecl()); + for (const auto &Base : RD->bases()) { + assert(Base.getType()->isRecordType() && + "Base class that isn't a record?"); + const RecordType *RT = Base.getType()->getAs(); + if (Visited.insert(RT).second) + ToVisit.push_back(Base.getType()->getAs()); + } + }; + + // Set up the loop by adding all the bases. + AddBases(RecordT); + + // Search each path of bases until we either run into a successful match + // (where all bases of it are invalid), or we run out of bases. + while (!ToVisit.empty()) { + const RecordType *NextT = ToVisit.pop_back_val(); + + SmallVector DeducedCopy(Deduced.begin(), + Deduced.end()); + TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); + Sema::TemplateDeductionResult BaseResult = + DeduceTemplateArguments(S, TemplateParams, SpecParam, + QualType(NextT, 0), BaseInfo, DeducedCopy); + + // If this was a successful deduction, add it to the list of matches, + // otherwise we need to continue searching its bases. + if (BaseResult == Sema::TDK_Success) + Matches.insert({NextT, DeducedCopy}); + else + AddBases(NextT); + } + + // At this point, 'Matches' contains a list of seemingly valid bases, however + // in the event that we have more than 1 match, it is possible that the base + // of one of the matches might be disqualified for being a base of another + // valid match. We can count on cyclical instantiations being invalid to + // simplify the disqualifications. That is, if A & B are both matches, and B + // inherits from A (disqualifying A), we know that A cannot inherit from B. + if (Matches.size() > 1) { + Visited.clear(); + for (const auto &Match : Matches) + AddBases(Match.first); + + // We can give up once we have a single item (or have run out of things to + // search) since cyclical inheritence isn't valid. + while (Matches.size() > 1 && !ToVisit.empty()) { + const RecordType *NextT = ToVisit.pop_back_val(); + Matches.erase(NextT); + + // Always add all bases, since the inheritence tree can contain + // disqualifications for multiple matches. + AddBases(NextT); + } + } + + if (Matches.empty()) + return Sema::TDK_Invalid; + if (Matches.size() > 1) + return Sema::TDK_MiscellaneousDeductionFailure; + + std::swap(Matches.front().second, Deduced); + return Sema::TDK_Success; +} + /// Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -1787,78 +1901,15 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, if (!S.isCompleteType(Info.getLocation(), Arg)) return Result; - // C++14 [temp.deduct.call] p4b3: - // If P is a class and P has the form simple-template-id, then the - // transformed A can be a derived class of the deduced A. Likewise if - // P is a pointer to a class of the form simple-template-id, the - // transformed A can be a pointer to a derived class pointed to by the - // deduced A. - // - // These alternatives are considered only if type deduction would - // otherwise fail. If they yield more than one possible deduced A, the - // type deduction fails. - // Reset the incorrectly deduced argument from above. Deduced = DeducedOrig; - // Use data recursion to crawl through the list of base classes. - // Visited contains the set of nodes we have already visited, while - // ToVisit is our stack of records that we still need to visit. - llvm::SmallPtrSet Visited; - SmallVector ToVisit; - ToVisit.push_back(RecordT); - bool Successful = false; - SmallVector SuccessfulDeduced; - while (!ToVisit.empty()) { - // Retrieve the next class in the inheritance hierarchy. - const RecordType *NextT = ToVisit.pop_back_val(); - - // If we have already seen this type, skip it. - if (!Visited.insert(NextT).second) - continue; - - // If this is a base class, try to perform template argument - // deduction from it. - if (NextT != RecordT) { - TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); - Sema::TemplateDeductionResult BaseResult = - DeduceTemplateArguments(S, TemplateParams, SpecParam, - QualType(NextT, 0), BaseInfo, Deduced); - - // If template argument deduction for this base was successful, - // note that we had some success. Otherwise, ignore any deductions - // from this base class. - if (BaseResult == Sema::TDK_Success) { - // If we've already seen some success, then deduction fails due to - // an ambiguity (temp.deduct.call p5). - if (Successful) - return Sema::TDK_MiscellaneousDeductionFailure; - - Successful = true; - std::swap(SuccessfulDeduced, Deduced); - - Info.Param = BaseInfo.Param; - Info.FirstArg = BaseInfo.FirstArg; - Info.SecondArg = BaseInfo.SecondArg; - } - - Deduced = DeducedOrig; - } - - // Visit base classes - CXXRecordDecl *Next = cast(NextT->getDecl()); - for (const auto &Base : Next->bases()) { - assert(Base.getType()->isRecordType() && - "Base class that isn't a record?"); - ToVisit.push_back(Base.getType()->getAs()); - } - } - - if (Successful) { - std::swap(SuccessfulDeduced, Deduced); - return Sema::TDK_Success; - } + // Check bases according to C++14 [temp.deduct.call] p4b3: + Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases( + S, RecordT, TemplateParams, SpecParam, Info, Deduced); + if (BaseResult != Sema::TDK_Invalid) + return BaseResult; return Result; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 01a0f51c81cee..14245f0392d6c 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -5136,7 +5136,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // is an incomplete type (C99 6.2.5p19) and function decls cannot // have parameters of incomplete type. if (FTI.NumParams != 1 || FTI.isVariadic) { - S.Diag(DeclType.Loc, diag::err_void_only_param); + S.Diag(FTI.Params[i].IdentLoc, diag::err_void_only_param); ParamTy = Context.IntTy; Param->setType(ParamTy); } else if (FTI.Params[i].Ident) { diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 9be1fdeb3ebfa..31f971e33cb29 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -127,6 +127,7 @@ add_clang_library(clangStaticAnalyzerCheckers WebKit/PtrTypesSemantics.cpp WebKit/RefCntblBaseVirtualDtorChecker.cpp WebKit/UncountedCallArgsChecker.cpp + WebKit/UncountedLambdaCapturesChecker.cpp LINK_LIBS clangAST diff --git a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp index 1ef70b650414e..56c6f8d02e0f6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp @@ -119,10 +119,10 @@ static const NoteTag *getNoteTag(CheckerContext &C, Out << "Assuming "; if (const auto *DRE = dyn_cast(Object)) { - Out << '\'' << DRE->getDecl()->getNameAsString() << '\''; + Out << '\'' << DRE->getDecl()->getDeclName() << '\''; } else if (const auto *ME = dyn_cast(Object)) { Out << (IsKnownCast ? "Field '" : "field '") - << ME->getMemberDecl()->getNameAsString() << '\''; + << ME->getMemberDecl()->getDeclName() << '\''; } else { Out << (IsKnownCast ? "The object" : "the object"); } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 13836f08a61ef..78b3c209ad6bc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -406,7 +406,7 @@ ProgramStateRef ObjCDeallocChecker::evalAssume(ProgramStateRef State, SVal Cond, if (State->get().isEmpty()) return State; - auto *CondBSE = dyn_cast_or_null(Cond.getAsSymExpr()); + auto *CondBSE = dyn_cast_or_null(Cond.getAsSymbol()); if (!CondBSE) return State; diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp index fc35082705fa6..b2822e5307f3a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -324,7 +324,7 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call, if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); - OS << "Function '" << FuncDecl->getNameAsString() + OS << "Function '" << FuncDecl->getDeclName() << "' returns an open handle"; return OS.str(); } else diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp index 632de9e5dc832..ab5e6a1c9991f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -109,7 +109,7 @@ class IteratorModeling bool Postfix) const; void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, OverloadedOperatorKind Op, const SVal &RetVal, - const SVal &LHS, const SVal &RHS) const; + const SVal &Iterator, const SVal &Amount) const; void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator, OverloadedOperatorKind OK, SVal Offset) const; void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter, @@ -262,20 +262,30 @@ void IteratorModeling::checkPostStmt(const UnaryOperator *UO, void IteratorModeling::checkPostStmt(const BinaryOperator *BO, CheckerContext &C) const { - ProgramStateRef State = C.getState(); - BinaryOperatorKind OK = BO->getOpcode(); - SVal RVal = State->getSVal(BO->getRHS(), C.getLocationContext()); + const ProgramStateRef State = C.getState(); + const BinaryOperatorKind OK = BO->getOpcode(); + const Expr *const LHS = BO->getLHS(); + const Expr *const RHS = BO->getRHS(); + const SVal LVal = State->getSVal(LHS, C.getLocationContext()); + const SVal RVal = State->getSVal(RHS, C.getLocationContext()); if (isSimpleComparisonOperator(BO->getOpcode())) { - SVal LVal = State->getSVal(BO->getLHS(), C.getLocationContext()); SVal Result = State->getSVal(BO, C.getLocationContext()); handleComparison(C, BO, Result, LVal, RVal, BinaryOperator::getOverloadedOperator(OK)); } else if (isRandomIncrOrDecrOperator(OK)) { - if (!BO->getRHS()->getType()->isIntegralOrEnumerationType()) + // In case of operator+ the iterator can be either on the LHS (eg.: it + 1), + // or on the RHS (eg.: 1 + it). Both cases are modeled. + const bool IsIterOnLHS = BO->getLHS()->getType()->isPointerType(); + const Expr *const &IterExpr = IsIterOnLHS ? LHS : RHS; + const Expr *const &AmountExpr = IsIterOnLHS ? RHS : LHS; + + // The non-iterator side must have an integral or enumeration type. + if (!AmountExpr->getType()->isIntegralOrEnumerationType()) return; - handlePtrIncrOrDecr(C, BO->getLHS(), - BinaryOperator::getOverloadedOperator(OK), RVal); + const SVal &AmountVal = IsIterOnLHS ? RVal : LVal; + handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK), + AmountVal); } } @@ -368,11 +378,24 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C, InstCall->getCXXThisVal(), Call.getArgSVal(0)); return; } - } else { - if (Call.getNumArgs() >= 2 && - Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { + } else if (Call.getNumArgs() >= 2) { + const Expr *FirstArg = Call.getArgExpr(0); + const Expr *SecondArg = Call.getArgExpr(1); + const QualType FirstType = FirstArg->getType(); + const QualType SecondType = SecondArg->getType(); + + if (FirstType->isIntegralOrEnumerationType() || + SecondType->isIntegralOrEnumerationType()) { + // In case of operator+ the iterator can be either on the LHS (eg.: + // it + 1), or on the RHS (eg.: 1 + it). Both cases are modeled. + const bool IsIterFirst = FirstType->isStructureOrClassType(); + const SVal FirstArg = Call.getArgSVal(0); + const SVal SecondArg = Call.getArgSVal(1); + const SVal &Iterator = IsIterFirst ? FirstArg : SecondArg; + const SVal &Amount = IsIterFirst ? SecondArg : FirstArg; + handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(), - Call.getArgSVal(0), Call.getArgSVal(1)); + Iterator, Amount); return; } } @@ -564,35 +587,35 @@ void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal, C.addTransition(State); } -void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, - const Expr *CE, +void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, OverloadedOperatorKind Op, const SVal &RetVal, - const SVal &LHS, - const SVal &RHS) const { + const SVal &Iterator, + const SVal &Amount) const { // Increment or decrement the symbolic expressions which represents the // position of the iterator auto State = C.getState(); - const auto *Pos = getIteratorPosition(State, LHS); + const auto *Pos = getIteratorPosition(State, Iterator); if (!Pos) return; - const auto *value = &RHS; - SVal val; - if (auto loc = RHS.getAs()) { - val = State->getRawSVal(*loc); - value = &val; + const auto *Value = &Amount; + SVal Val; + if (auto LocAmount = Amount.getAs()) { + Val = State->getRawSVal(*LocAmount); + Value = &Val; } - auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal; + const auto &TgtVal = + (Op == OO_PlusEqual || Op == OO_MinusEqual) ? Iterator : RetVal; // `AdvancedState` is a state where the position of `LHS` is advanced. We // only need this state to retrieve the new position, but we do not want // to change the position of `LHS` (in every case). - auto AdvancedState = advancePosition(State, LHS, Op, *value); + auto AdvancedState = advancePosition(State, Iterator, Op, *Value); if (AdvancedState) { - const auto *NewPos = getIteratorPosition(AdvancedState, LHS); + const auto *NewPos = getIteratorPosition(AdvancedState, Iterator); assert(NewPos && "Iterator should have position after successful advancement"); diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index 87477e96d2d16..a157ee2da5df4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -509,7 +509,7 @@ ProgramStateRef MacOSKeychainAPIChecker::evalAssume(ProgramStateRef State, if (AMap.isEmpty()) return State; - auto *CondBSE = dyn_cast_or_null(Cond.getAsSymExpr()); + auto *CondBSE = dyn_cast_or_null(Cond.getAsSymbol()); if (!CondBSE) return State; BinaryOperator::Opcode OpCode = CondBSE->getOpcode(); diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index d5b0a5b2220ff..fc6d15371a2f3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -3301,14 +3301,16 @@ PathDiagnosticPieceRef MallocBugVisitor::VisitNode(const ExplodedNode *N, OS << "reallocated by call to '"; const Stmt *S = RSCurr->getStmt(); if (const auto *MemCallE = dyn_cast(S)) { - OS << MemCallE->getMethodDecl()->getNameAsString(); + OS << MemCallE->getMethodDecl()->getDeclName(); } else if (const auto *OpCallE = dyn_cast(S)) { - OS << OpCallE->getDirectCallee()->getNameAsString(); + OS << OpCallE->getDirectCallee()->getDeclName(); } else if (const auto *CallE = dyn_cast(S)) { auto &CEMgr = BRC.getStateManager().getCallEventManager(); CallEventRef<> Call = CEMgr.getSimpleCall(CallE, state, CurrentLC); - const auto *D = dyn_cast_or_null(Call->getDecl()); - OS << (D ? D->getNameAsString() : "unknown"); + if (const auto *D = dyn_cast_or_null(Call->getDecl())) + OS << D->getDeclName(); + else + OS << "unknown"; } OS << "'"; StackHint = std::make_unique( diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp index 7f0519c695b0f..da3ce01d032be 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -580,7 +580,7 @@ void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR, if (const auto DR = dyn_cast_or_null(unwrapRValueReferenceIndirection(MR))) { const auto *RegionDecl = cast(DR->getDecl()); - OS << " '" << RegionDecl->getNameAsString() << "'"; + OS << " '" << RegionDecl->getDeclName() << "'"; } ObjectKind OK = classifyObject(MR, RD); diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp index 1d8ed90f7590c..1d903530201f8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp @@ -177,7 +177,7 @@ static Optional findArgIdxOfSymbol(ProgramStateRef CurrSt, for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++) if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion()) if (const auto *TR = dyn_cast(MR)) - if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym) + if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymbol() == Sym) return Idx; return None; @@ -439,7 +439,7 @@ annotateStartParameter(const ExplodedNode *N, SymbolRef Sym, std::string s; llvm::raw_string_ostream os(s); - os << "Parameter '" << PVD->getNameAsString() << "' starts at +"; + os << "Parameter '" << PVD->getDeclName() << "' starts at +"; if (CurrT->getCount() == 1) { os << "1, as it is marked as consuming"; } else { diff --git a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp index 5b46ffb656cf8..71b2ab834a07a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp @@ -148,7 +148,7 @@ bool taint::isTainted(ProgramStateRef State, const Stmt *S, } bool taint::isTainted(ProgramStateRef State, SVal V, TaintTagType Kind) { - if (const SymExpr *Sym = V.getAsSymExpr()) + if (SymbolRef Sym = V.getAsSymbol()) return isTainted(State, Sym, Kind); if (const MemRegion *Reg = V.getAsRegion()) return isTainted(State, Reg, Kind); diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index f49ee5fa5ad37..1c589e3468c2d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -125,8 +125,8 @@ void VirtualCallChecker::checkPreCall(const CallEvent &Call, OS << "Call to "; if (IsPure) OS << "pure "; - OS << "virtual method '" << MD->getParent()->getNameAsString() - << "::" << MD->getNameAsString() << "' during "; + OS << "virtual method '" << MD->getParent()->getDeclName() + << "::" << MD->getDeclName() << "' during "; if (*ObState == ObjectState::CtorCalled) OS << "construction "; else diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp new file mode 100644 index 0000000000000..0a387592d350e --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp @@ -0,0 +1,106 @@ +//=======- UncountedLambdaCapturesChecker.cpp --------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DiagOutputUtils.h" +#include "PtrTypesSemantics.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" + +using namespace clang; +using namespace ento; + +namespace { +class UncountedLambdaCapturesChecker + : public Checker> { +private: + BugType Bug{this, "Lambda capture of uncounted variable", + "WebKit coding guidelines"}; + mutable BugReporter *BR; + +public: + void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, + BugReporter &BRArg) const { + BR = &BRArg; + + // The calls to checkAST* from AnalysisConsumer don't + // visit template instantiations or lambda classes. We + // want to visit those, so we make our own RecursiveASTVisitor. + struct LocalVisitor : public RecursiveASTVisitor { + const UncountedLambdaCapturesChecker *Checker; + explicit LocalVisitor(const UncountedLambdaCapturesChecker *Checker) + : Checker(Checker) { + assert(Checker); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { return false; } + + bool VisitLambdaExpr(LambdaExpr *L) { + Checker->visitLambdaExpr(L); + return true; + } + }; + + LocalVisitor visitor(this); + visitor.TraverseDecl(const_cast(TUD)); + } + + void visitLambdaExpr(LambdaExpr *L) const { + for (const LambdaCapture &C : L->captures()) { + if (C.capturesVariable()) { + VarDecl *CapturedVar = C.getCapturedVar(); + if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) { + if (isUncountedPtr(CapturedVarType)) { + reportBug(C, CapturedVar, CapturedVarType); + } + } + } + } + } + + void reportBug(const LambdaCapture &Capture, VarDecl *CapturedVar, + const Type *T) const { + assert(CapturedVar); + + SmallString<100> Buf; + llvm::raw_svector_ostream Os(Buf); + + if (Capture.isExplicit()) { + Os << "Captured "; + } else { + Os << "Implicitly captured "; + } + if (T->isPointerType()) { + Os << "raw-pointer "; + } else { + assert(T->isReferenceType()); + Os << "reference "; + } + + printQuotedQualifiedName(Os, Capture.getCapturedVar()); + Os << " to uncounted type is unsafe."; + + PathDiagnosticLocation BSLoc(Capture.getLocation(), BR->getSourceManager()); + auto Report = std::make_unique(Bug, Os.str(), BSLoc); + BR->emitReport(std::move(Report)); + } +}; +} // namespace + +void ento::registerUncountedLambdaCapturesChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterUncountedLambdaCapturesChecker( + const CheckerManager &mgr) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 265dcd134213d..7888029399f1d 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -169,7 +169,7 @@ class ConstructedObjectKey { if (S) { S->printJson(Out, Helper, PP, /*AddQuotes=*/true); } else { - Out << '\"' << I->getAnyMember()->getNameAsString() << '\"'; + Out << '\"' << I->getAnyMember()->getDeclName() << '\"'; } } diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 006a4006b7fc9..1ccb0de92fba3 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -582,9 +582,6 @@ bool ScanReachableSymbols::scan(SVal val) { if (SymbolRef Sym = val.getAsSymbol()) return scan(Sym); - if (const SymExpr *Sym = val.getAsSymbolicExpression()) - return scan(Sym); - if (Optional X = val.getAs()) return scan(*X); diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index c00a2c8ba8a2c..5b6b6973b310c 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -377,8 +377,8 @@ Optional SValBuilder::getConstantVal(const Expr *E) { SVal SValBuilder::makeSymExprValNN(BinaryOperator::Opcode Op, NonLoc LHS, NonLoc RHS, QualType ResultTy) { - const SymExpr *symLHS = LHS.getAsSymExpr(); - const SymExpr *symRHS = RHS.getAsSymExpr(); + SymbolRef symLHS = LHS.getAsSymbol(); + SymbolRef symRHS = RHS.getAsSymbol(); // TODO: When the Max Complexity is reached, we should conjure a symbol // instead of generating an Unknown value and propagate the taint info to it. @@ -492,7 +492,7 @@ SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val, if (getContext().getTypeSize(castTy) >= getContext().getTypeSize(originalTy)) return evalCast(val, castTy, originalTy); - const SymExpr *se = val.getAsSymbolicExpression(); + SymbolRef se = val.getAsSymbol(); if (!se) // Let evalCast handle non symbolic expressions. return evalCast(val, castTy, originalTy); diff --git a/clang/lib/StaticAnalyzer/Core/SVals.cpp b/clang/lib/StaticAnalyzer/Core/SVals.cpp index 9b5de6c3eb92b..465800fa67fce 100644 --- a/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -116,8 +116,6 @@ SymbolRef SVal::getLocSymbolInBase() const { return nullptr; } -// TODO: The next 3 functions have to be simplified. - /// If this SVal wraps a symbol return that SymbolRef. /// Otherwise, return 0. /// @@ -132,22 +130,6 @@ SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const { return getAsLocSymbol(IncludeBaseRegions); } -/// getAsSymbolicExpression - If this Sval wraps a symbolic expression then -/// return that expression. Otherwise return NULL. -const SymExpr *SVal::getAsSymbolicExpression() const { - if (Optional X = getAs()) - return X->getSymbol(); - - return getAsSymbol(); -} - -const SymExpr* SVal::getAsSymExpr() const { - const SymExpr* Sym = getAsSymbol(); - if (!Sym) - Sym = getAsSymbolicExpression(); - return Sym; -} - const MemRegion *SVal::getAsRegion() const { if (Optional X = getAs()) return X->getRegion(); diff --git a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index 3709106ad44ce..f96974f97dcc5 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -57,7 +57,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State, // SymIntExprs. if (!canReasonAbout(Cond)) { // Just add the constraint to the expression without trying to simplify. - SymbolRef Sym = Cond.getAsSymExpr(); + SymbolRef Sym = Cond.getAsSymbol(); assert(Sym); return assumeSymUnsupported(State, Sym, Assumption); } @@ -101,7 +101,7 @@ ProgramStateRef SimpleConstraintManager::assumeInclusiveRange( if (!canReasonAbout(Value)) { // Just add the constraint to the expression without trying to simplify. - SymbolRef Sym = Value.getAsSymExpr(); + SymbolRef Sym = Value.getAsSymbol(); assert(Sym); return assumeSymInclusiveRange(State, Sym, From, To, InRange); } diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 2e269f6a596e8..a64ed78ac3458 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -86,7 +86,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { return makeLocAsInteger(LI->getLoc(), castSize); } - if (const SymExpr *se = val.getAsSymbolicExpression()) { + if (SymbolRef se = val.getAsSymbol()) { QualType T = Context.getCanonicalType(se->getType()); // If types are the same or both are integers, ignore the cast. // FIXME: Remove this hack when we support symbolic truncation/extension. diff --git a/clang/lib/Tooling/Refactoring/ASTSelection.cpp b/clang/lib/Tooling/Refactoring/ASTSelection.cpp index af1eb491a20a2..9485c8bc04ad0 100644 --- a/clang/lib/Tooling/Refactoring/ASTSelection.cpp +++ b/clang/lib/Tooling/Refactoring/ASTSelection.cpp @@ -218,7 +218,7 @@ static void dump(const SelectedASTNode &Node, llvm::raw_ostream &OS, if (const Decl *D = Node.Node.get()) { OS << D->getDeclKindName() << "Decl"; if (const auto *ND = dyn_cast(D)) - OS << " \"" << ND->getNameAsString() << '"'; + OS << " \"" << ND->getDeclName() << '"'; } else if (const Stmt *S = Node.Node.get()) { OS << S->getStmtClassName(); } diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 1f192180ec451..15b7c8fab1982 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -939,6 +939,8 @@ class BuildTreeVisitor : public RecursiveASTVisitor { return true; } + // FIXME: Deleting the `TraverseParenTypeLoc` override doesn't change test + // results. Find test coverage or remove it. bool TraverseParenTypeLoc(ParenTypeLoc L) { // We reverse order of traversal to get the proper syntax structure. if (!WalkUpFromParenTypeLoc(L)) @@ -987,6 +989,16 @@ class BuildTreeVisitor : public RecursiveASTVisitor { return WalkUpFromFunctionTypeLoc(L); } + bool TraverseMemberPointerTypeLoc(MemberPointerTypeLoc L) { + // In the source code "void (Y::*mp)()" `MemberPointerTypeLoc` corresponds + // to "Y::*" but it points to a `ParenTypeLoc` that corresponds to + // "(Y::*mp)" We thus reverse the order of traversal to get the proper + // syntax structure. + if (!WalkUpFromMemberPointerTypeLoc(L)) + return false; + return TraverseTypeLoc(L.getPointeeLoc()); + } + bool WalkUpFromMemberPointerTypeLoc(MemberPointerTypeLoc L) { auto SR = L.getLocalSourceRange(); Builder.foldNode(Builder.getRange(SR), diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp index 2435ae0a91dd6..eced68fa2443f 100644 --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -230,37 +230,7 @@ syntax::Leaf *syntax::ParenExpression::closeParen() { findChild(syntax::NodeRole::CloseParen)); } -syntax::Leaf *syntax::IntegerLiteralExpression::literalToken() { - return llvm::cast_or_null( - findChild(syntax::NodeRole::LiteralToken)); -} - -syntax::Leaf *syntax::CharacterLiteralExpression::literalToken() { - return llvm::cast_or_null( - findChild(syntax::NodeRole::LiteralToken)); -} - -syntax::Leaf *syntax::FloatingLiteralExpression::literalToken() { - return llvm::cast_or_null( - findChild(syntax::NodeRole::LiteralToken)); -} - -syntax::Leaf *syntax::StringLiteralExpression::literalToken() { - return llvm::cast_or_null( - findChild(syntax::NodeRole::LiteralToken)); -} - -syntax::Leaf *syntax::BoolLiteralExpression::literalToken() { - return llvm::cast_or_null( - findChild(syntax::NodeRole::LiteralToken)); -} - -syntax::Leaf *syntax::CxxNullPtrExpression::nullPtrKeyword() { - return llvm::cast_or_null( - findChild(syntax::NodeRole::LiteralToken)); -} - -syntax::Leaf *syntax::UserDefinedLiteralExpression::literalToken() { +syntax::Leaf *syntax::LiteralExpression::literalToken() { return llvm::cast_or_null( findChild(syntax::NodeRole::LiteralToken)); } diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 40b6cff0d627a..1ee8ce28c2efa 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -245,27 +245,38 @@ std::string getAbsolutePath(StringRef File) { void addTargetAndModeForProgramName(std::vector &CommandLine, StringRef InvokedAs) { - if (!CommandLine.empty() && !InvokedAs.empty()) { - bool AlreadyHasTarget = false; - bool AlreadyHasMode = false; - // Skip CommandLine[0]. - for (auto Token = ++CommandLine.begin(); Token != CommandLine.end(); - ++Token) { - StringRef TokenRef(*Token); - AlreadyHasTarget |= - (TokenRef == "-target" || TokenRef.startswith("-target=")); - AlreadyHasMode |= (TokenRef == "--driver-mode" || - TokenRef.startswith("--driver-mode=")); - } - auto TargetMode = - driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs); - if (!AlreadyHasMode && TargetMode.DriverMode) { - CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode); - } - if (!AlreadyHasTarget && TargetMode.TargetIsValid) { - CommandLine.insert(++CommandLine.begin(), {"-target", - TargetMode.TargetPrefix}); - } + if (CommandLine.empty() || InvokedAs.empty()) + return; + const auto &Table = driver::getDriverOptTable(); + // --target=X + const std::string TargetOPT = + Table.getOption(driver::options::OPT_target).getPrefixedName(); + // -target X + const std::string TargetOPTLegacy = + Table.getOption(driver::options::OPT_target_legacy_spelling) + .getPrefixedName(); + // --driver-mode=X + const std::string DriverModeOPT = + Table.getOption(driver::options::OPT_driver_mode).getPrefixedName(); + auto TargetMode = + driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs); + // No need to search for target args if we don't have a target/mode to insert. + bool ShouldAddTarget = TargetMode.TargetIsValid; + bool ShouldAddMode = TargetMode.DriverMode != nullptr; + // Skip CommandLine[0]. + for (auto Token = ++CommandLine.begin(); Token != CommandLine.end(); + ++Token) { + StringRef TokenRef(*Token); + ShouldAddTarget = ShouldAddTarget && !TokenRef.startswith(TargetOPT) && + !TokenRef.equals(TargetOPTLegacy); + ShouldAddMode = ShouldAddMode && !TokenRef.startswith(DriverModeOPT); + } + if (ShouldAddMode) { + CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode); + } + if (ShouldAddTarget) { + CommandLine.insert(++CommandLine.begin(), + TargetOPT + TargetMode.TargetPrefix); } } diff --git a/clang/test/AST/ast-dump-concepts.cpp b/clang/test/AST/ast-dump-concepts.cpp index 3429fa6b46be5..630a953976fc0 100644 --- a/clang/test/AST/ast-dump-concepts.cpp +++ b/clang/test/AST/ast-dump-concepts.cpp @@ -15,7 +15,7 @@ concept binary_concept = true; template struct Foo { // CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept' - // CHECK-NEXT: |-ConceptSpecializationExpr {{.*}} 'bool' + // CHECK-NEXT: |-ConceptSpecializationExpr {{.*}} 'bool' Concept {{.*}} 'binary_concept' // CHECK-NEXT: `-TemplateArgument {{.*}} type 'int' template R> Foo(R); @@ -24,4 +24,13 @@ struct Foo { // CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} 'bool' template Foo(R); + + // CHECK: FunctionTemplateDecl {{.*}} {{.*}} Foo + template + Foo(R, int) requires unary_concept; + + // CHECK: FunctionTemplateDecl {{.*}} {{.*}} Foo + template + Foo(R, char) requires unary_concept { + } }; diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp new file mode 100644 index 0000000000000..85dd77f9a8774 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.UncountedLambdaCapturesChecker %s 2>&1 | FileCheck %s --strict-whitespace +#include "mock-types.h" + +void raw_ptr() { + RefCountable* ref_countable = nullptr; + auto foo1 = [ref_countable](){}; + // CHECK: warning: Captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] + // CHECK-NEXT:{{^}} auto foo1 = [ref_countable](){}; + // CHECK-NEXT:{{^}} ^ + auto foo2 = [&ref_countable](){}; + // CHECK: warning: Captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] + auto foo3 = [&](){ ref_countable = nullptr; }; + // CHECK: warning: Implicitly captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] + // CHECK-NEXT:{{^}} auto foo3 = [&](){ ref_countable = nullptr; }; + // CHECK-NEXT:{{^}} ^ + auto foo4 = [=](){ (void) ref_countable; }; + // CHECK: warning: Implicitly captured raw-pointer 'ref_countable' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] +} + +void references() { + RefCountable automatic; + RefCountable& ref_countable_ref = automatic; + + auto foo1 = [ref_countable_ref](){}; + // CHECK: warning: Captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] + auto foo2 = [&ref_countable_ref](){}; + // CHECK: warning: Captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] + auto foo3 = [&](){ (void) ref_countable_ref; }; + // CHECK: warning: Implicitly captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] + auto foo4 = [=](){ (void) ref_countable_ref; }; + // CHECK: warning: Implicitly captured reference 'ref_countable_ref' to uncounted type is unsafe [webkit.UncountedLambdaCapturesChecker] +} + +void quiet() { +// This code is not expected to trigger any warnings. + { + RefCountable automatic; + RefCountable &ref_countable_ref = automatic; + } + + auto foo3 = [&]() {}; + auto foo4 = [=]() {}; + RefCountable *ref_countable = nullptr; +} diff --git a/clang/test/Analysis/cfg.cpp b/clang/test/Analysis/cfg.cpp index 0159a3c0488ce..5f2b365eeb4e7 100644 --- a/clang/test/Analysis/cfg.cpp +++ b/clang/test/Analysis/cfg.cpp @@ -575,6 +575,24 @@ int vla_evaluate(int x) { return x; } +// CHECK-LABEL: void CommaTemp::f() +// CHECK: [B1] +// CHECK-NEXT: 1: CommaTemp::A() (CXXConstructExpr, +// CHECK-NEXT: 2: [B1.1] (BindTemporary) +// CHECK-NEXT: 3: CommaTemp::B() (CXXConstructExpr, +// CHECK-NEXT: 4: [B1.3] (BindTemporary) +// CHECK-NEXT: 5: ... , [B1.4] +// CHECK-NEXT: 6: ~CommaTemp::B() (Temporary object destructor) +// CHECK-NEXT: 7: ~CommaTemp::A() (Temporary object destructor) +namespace CommaTemp { + struct A { ~A(); }; + struct B { ~B(); }; + void f(); +} +void CommaTemp::f() { + A(), B(); +} + // CHECK-LABEL: template<> int *PR18472() // CHECK: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1 diff --git a/clang/test/Analysis/iterator-modeling.cpp b/clang/test/Analysis/iterator-modeling.cpp index 0b76b0bfa7232..f1538839d06c8 100644 --- a/clang/test/Analysis/iterator-modeling.cpp +++ b/clang/test/Analysis/iterator-modeling.cpp @@ -149,7 +149,7 @@ void copy(const std::vector &v) { clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re {{$v.end(){{$}}}} } -void plus(const std::vector &v) { +void plus_lhs(const std::vector &v) { auto i1 = v.begin(); clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); @@ -161,7 +161,19 @@ void plus(const std::vector &v) { clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re{{$v.begin() + 2{{$}}}} } -void plus_negative(const std::vector &v) { +void plus_rhs(const std::vector &v) { + auto i1 = v.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(v), "$v.begin()"); + + auto i2 = 2 + i1; + + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &v); // expected-warning{{TRUE}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning-re{{$v.begin(){{$}}}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re{{$v.begin() + 2{{$}}}} +} + +void plus_lhs_negative(const std::vector &v) { auto i1 = v.end(); clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); @@ -173,6 +185,18 @@ void plus_negative(const std::vector &v) { clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re {{$v.end() - 2{{$}}}} } +void plus_rhs_negative(const std::vector &v) { + auto i1 = v.end(); + + clang_analyzer_denote(clang_analyzer_container_end(v), "$v.end()"); + + auto i2 = (-2) + i1; + + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &v); // expected-warning{{TRUE}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning-re {{$v.end(){{$}}}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning-re {{$v.end() - 2{{$}}}} +} + void minus(const std::vector &v) { auto i1 = v.end(); @@ -1955,7 +1979,7 @@ void minus_equal_ptr_iterator_variable(const cont_with_ptr_iterator &c, i -= n; // no-crash } -void plus_ptr_iterator(const cont_with_ptr_iterator &c) { +void plus_lhs_ptr_iterator(const cont_with_ptr_iterator &c) { auto i1 = c.begin(); clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); @@ -1967,6 +1991,18 @@ void plus_ptr_iterator(const cont_with_ptr_iterator &c) { clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.begin() + 2}} } +void plus_rhs_ptr_iterator(const cont_with_ptr_iterator &c) { + auto i1 = c.begin(); + + clang_analyzer_denote(clang_analyzer_container_begin(c), "$c.begin()"); + + auto i2 = 2 + i1; + + clang_analyzer_eval(clang_analyzer_iterator_container(i2) == &c); // expected-warning{{TRUE}} + clang_analyzer_express(clang_analyzer_iterator_position(i1)); // expected-warning{{$c.begin()}} + clang_analyzer_express(clang_analyzer_iterator_position(i2)); // expected-warning{{$c.begin() + 2}} +} + void minus_ptr_iterator(const cont_with_ptr_iterator &c) { auto i1 = c.end(); diff --git a/clang/test/CXX/drs/dr23xx.cpp b/clang/test/CXX/drs/dr23xx.cpp index 3268838ac6c85..c265ebbe359cb 100644 --- a/clang/test/CXX/drs/dr23xx.cpp +++ b/clang/test/CXX/drs/dr23xx.cpp @@ -113,3 +113,35 @@ namespace dr2387 { // dr2387: 9 extern template const int d; #endif } + +#if __cplusplus >= 201103L +namespace dr2303 { // dr2303: 12 +template +struct A; +template <> +struct A<> {}; +template +struct A : A {}; +struct B : A {}; +struct C : A, A {}; // expected-warning {{direct base 'A' is inaccessible}} +struct D : A, A {}; // expected-warning {{direct base 'A' is inaccessible}} +struct E : A {}; +struct F : B, E {}; + +template +void f(const A &) { + static_assert(sizeof...(T) == 2, "Should only match A"); +} +template +void f2(const A *); + +void g() { + f(B{}); // This is no longer ambiguous. + B b; + f2(&b); + f(C{}); + f(D{}); + f(F{}); // expected-error {{ambiguous conversion from derived class}} +} +} //namespace dr2303 +#endif diff --git a/clang/test/CodeGen/atomics-sema-alignment.c b/clang/test/CodeGen/atomics-sema-alignment.c index 9443af354ec5d..d0058f1da8b01 100644 --- a/clang/test/CodeGen/atomics-sema-alignment.c +++ b/clang/test/CodeGen/atomics-sema-alignment.c @@ -12,10 +12,10 @@ typedef int __attribute__((aligned(1))) unaligned_int; void func(IntPair *p) { IntPair res; - __atomic_load(p, &res, 0); // expected-warning {{misaligned atomic operation may incur significant performance penalty}} - __atomic_store(p, &res, 0); // expected-warning {{misaligned atomic operation may incur significant performance penalty}} - __atomic_fetch_add((unaligned_int *)p, 1, 2); // expected-warning {{misaligned atomic operation may incur significant performance penalty}} - __atomic_fetch_sub((unaligned_int *)p, 1, 3); // expected-warning {{misaligned atomic operation may incur significant performance penalty}} + __atomic_load(p, &res, 0); // expected-warning {{misaligned atomic operation may incur significant performance penalty; the expected alignment (8 bytes) exceeds the actual alignment (4 bytes)}} + __atomic_store(p, &res, 0); // expected-warning {{misaligned atomic operation may incur significant performance penalty; the expected alignment (8 bytes) exceeds the actual alignment (4 bytes)}} + __atomic_fetch_add((unaligned_int *)p, 1, 2); // expected-warning {{misaligned atomic operation may incur significant performance penalty; the expected alignment (4 bytes) exceeds the actual alignment (1 bytes)}} + __atomic_fetch_sub((unaligned_int *)p, 1, 3); // expected-warning {{misaligned atomic operation may incur significant performance penalty; the expected alignment (4 bytes) exceeds the actual alignment (1 bytes)}} } void func1(LongStruct *p) { @@ -25,3 +25,24 @@ void func1(LongStruct *p) { __atomic_fetch_add((int *)p, 1, 2); __atomic_fetch_sub((int *)p, 1, 3); } + +typedef struct { + void *a; + void *b; +} Foo; + +typedef struct { + void *a; + void *b; + void *c; + void *d; +} __attribute__((aligned(32))) ThirtyTwo; + +void braz(Foo *foo, ThirtyTwo *braz) { + Foo bar; + __atomic_load(foo, &bar, __ATOMIC_RELAXED); // expected-warning {{misaligned atomic operation may incur significant performance penalty; the expected alignment (16 bytes) exceeds the actual alignment (8 bytes)}} + + ThirtyTwo thirtyTwo1; + ThirtyTwo thirtyTwo2; + __atomic_load(&thirtyTwo1, &thirtyTwo2, __ATOMIC_RELAXED); // expected-warning {{large atomic operation may incur significant performance penalty; the access size (32 bytes) exceeds the max lock-free size (16 bytes)}} +} diff --git a/clang/test/CodeGen/builtin-bpf-btf-type-id.c b/clang/test/CodeGen/builtin-bpf-btf-type-id.c index f60e3ca68a43c..5143deeff3c62 100644 --- a/clang/test/CodeGen/builtin-bpf-btf-type-id.c +++ b/clang/test/CodeGen/builtin-bpf-btf-type-id.c @@ -4,10 +4,22 @@ unsigned test1(int a) { return __builtin_btf_type_id(a, 0); } unsigned test2(int a) { return __builtin_btf_type_id(&a, 0); } +struct t1 { int a; }; +typedef struct t1 __t1; +unsigned test3() { + return __builtin_btf_type_id(*(struct t1 *)0, 1) + + __builtin_btf_type_id(*(__t1 *)0, 1); +} + // CHECK: define dso_local i32 @test1 -// CHECK: call i32 @llvm.bpf.btf.type.id.p0i32.i32(i32* %{{[0-9a-z.]+}}, i32 1, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT:[0-9]+]] +// CHECK: call i32 @llvm.bpf.btf.type.id(i32 0, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT:[0-9]+]] // CHECK: define dso_local i32 @test2 -// CHECK: call i32 @llvm.bpf.btf.type.id.p0i32.i32(i32* %{{[0-9a-z.]+}}, i32 0, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT_POINTER:[0-9]+]] +// CHECK: call i32 @llvm.bpf.btf.type.id(i32 1, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[INT_POINTER:[0-9]+]] +// CHECK: define dso_local i32 @test3 +// CHECK: call i32 @llvm.bpf.btf.type.id(i32 2, i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_T1:[0-9]+]] +// CHECK: call i32 @llvm.bpf.btf.type.id(i32 3, i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_T1:[0-9]+]] // // CHECK: ![[INT]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed // CHECK: ![[INT_POINTER]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[INT]], size: 64 +// CHECK: ![[TYPEDEF_T1]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__t1" +// CHECK: ![[STRUCT_T1]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t1" diff --git a/clang/test/CodeGen/builtins-bpf-preserve-field-info-3.c b/clang/test/CodeGen/builtins-bpf-preserve-field-info-3.c new file mode 100644 index 0000000000000..f59d88b663e44 --- /dev/null +++ b/clang/test/CodeGen/builtins-bpf-preserve-field-info-3.c @@ -0,0 +1,41 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define _(x, y) (__builtin_preserve_type_info((x), (y))) + +struct s { + char a; +}; +typedef int __int; +enum AA { + VAL1 = 1, + VAL2 = 2, +}; + +unsigned unit1() { + struct s v = {}; + return _(v, 0) + _(*(struct s *)0, 0); +} + +// CHECK: call i32 @llvm.bpf.preserve.type.info(i32 0, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.type.info(i32 1, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[STRUCT_S]] + +unsigned unit2() { + __int n; + return _(n, 1) + _(*(__int *)0, 1); +} + +// CHECK: call i32 @llvm.bpf.preserve.type.info(i32 2, i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_INT:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.type.info(i32 3, i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_INT]] + +unsigned unit3() { + enum AA t; + return _(t, 0) + _(*(enum AA *)0, 1); +} + +// CHECK: call i32 @llvm.bpf.preserve.type.info(i32 4, i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[ENUM_AA:[0-9]+]] +// CHECK: call i32 @llvm.bpf.preserve.type.info(i32 5, i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[ENUM_AA]] + +// CHECK: ![[ENUM_AA]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA" +// CHECK: ![[TYPEDEF_INT]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__int" +// CHECK: ![[STRUCT_S]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s" diff --git a/clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c b/clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c new file mode 100644 index 0000000000000..390b4f9bc07de --- /dev/null +++ b/clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c @@ -0,0 +1,32 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s + +#define _(x, y) (__builtin_preserve_enum_value((x), (y))) + +enum AA { + VAL1 = 2, + VAL2 = 0xffffffff80000000UL, +}; +typedef enum { VAL10 = -2, VAL11 = 0xffff8000, } __BB; + +unsigned unit1() { + return _(*(enum AA *)VAL1, 0) + _(*(__BB *)VAL10, 1); +} + +unsigned unit2() { + return _(*(enum AA *)VAL2, 0) + _(*(__BB *)VAL11, 1); +} + +// CHECK: @0 = private unnamed_addr constant [7 x i8] c"VAL1:2\00", align 1 +// CHECK: @1 = private unnamed_addr constant [9 x i8] c"VAL10:-2\00", align 1 +// CHECK: @2 = private unnamed_addr constant [17 x i8] c"VAL2:-2147483648\00", align 1 +// CHECK: @3 = private unnamed_addr constant [17 x i8] c"VAL11:4294934528\00", align 1 + +// CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 0, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i32 0, i32 0), i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[ENUM_AA:[0-9]+]] +// CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 1, i8* getelementptr inbounds ([9 x i8], [9 x i8]* @1, i32 0, i32 0), i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_ENUM:[0-9]+]] + +// CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 2, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @2, i32 0, i32 0), i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[ENUM_AA]] +// CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 3, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @3, i32 0, i32 0), i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_ENUM]] + +// CHECK: ![[ENUM_AA]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA" +// CHECK: ![[TYPEDEF_ENUM]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__BB" diff --git a/clang/test/CodeGen/builtins-ppc-p10vector.c b/clang/test/CodeGen/builtins-ppc-p10vector.c index e67018b062141..571d33d34a220 100644 --- a/clang/test/CodeGen/builtins-ppc-p10vector.c +++ b/clang/test/CodeGen/builtins-ppc-p10vector.c @@ -25,6 +25,66 @@ unsigned char uca; unsigned short usa; unsigned long long ulla; +vector signed long long test_vec_mul_sll(void) { + // CHECK: mul <2 x i64> + // CHECK-NEXT: ret <2 x i64> + return vec_mul(vslla, vsllb); +} + +vector unsigned long long test_vec_mul_ull(void) { + // CHECK: mul <2 x i64> + // CHECK-NEXT: ret <2 x i64> + return vec_mul(vulla, vullb); +} + +vector signed int test_vec_div_si(void) { + // CHECK: sdiv <4 x i32> + // CHECK-NEXT: ret <4 x i32> + return vec_div(vsia, vsib); +} + +vector unsigned int test_vec_div_ui(void) { + // CHECK: udiv <4 x i32> + // CHECK-NEXT: ret <4 x i32> + return vec_div(vuia, vuib); +} + +vector signed long long test_vec_div_sll(void) { + // CHECK: sdiv <2 x i64> + // CHECK-NEXT: ret <2 x i64> + return vec_div(vslla, vsllb); +} + +vector unsigned long long test_vec_div_ull(void) { + // CHECK: udiv <2 x i64> + // CHECK-NEXT: ret <2 x i64> + return vec_div(vulla, vullb); +} + +vector signed int test_vec_mod_si(void) { + // CHECK: srem <4 x i32> + // CHECK-NEXT: ret <4 x i32> + return vec_mod(vsia, vsib); +} + +vector unsigned int test_vec_mod_ui(void) { + // CHECK: urem <4 x i32> + // CHECK-NEXT: ret <4 x i32> + return vec_mod(vuia, vuib); +} + +vector signed long long test_vec_mod_sll(void) { + // CHECK: srem <2 x i64> + // CHECK-NEXT: ret <2 x i64> + return vec_mod(vslla, vsllb); +} + +vector unsigned long long test_vec_mod_ull(void) { + // CHECK: urem <2 x i64> + // CHECK-NEXT: ret <2 x i64> + return vec_mod(vulla, vullb); +} + vector unsigned long long test_vpdepd(void) { // CHECK: @llvm.ppc.altivec.vpdepd(<2 x i64> // CHECK-NEXT: ret <2 x i64> diff --git a/clang/test/CodeGen/builtins-wasm.c b/clang/test/CodeGen/builtins-wasm.c index 0f66fceef4cca..01e9273e0fb63 100644 --- a/clang/test/CodeGen/builtins-wasm.c +++ b/clang/test/CodeGen/builtins-wasm.c @@ -3,7 +3,7 @@ // RUN: not %clang_cc1 -triple wasm64-unknown-unknown -target-feature +nontrapping-fptoint -target-feature +exception-handling -target-feature +bulk-memory -target-feature +atomics -flax-vector-conversions=none -O3 -emit-llvm -o - %s 2>&1 | FileCheck %s -check-prefixes MISSING-SIMD // SIMD convenience types -typedef char i8x16 __attribute((vector_size(16))); +typedef signed char i8x16 __attribute((vector_size(16))); typedef short i16x8 __attribute((vector_size(16))); typedef int i32x4 __attribute((vector_size(16))); typedef long long i64x2 __attribute((vector_size(16))); @@ -201,7 +201,7 @@ int extract_lane_s_i8x16(i8x16 v) { // WEBASSEMBLY-NEXT: ret } -int extract_lane_u_i8x16(i8x16 v) { +int extract_lane_u_i8x16(u8x16 v) { return __builtin_wasm_extract_lane_u_i8x16(v, 13); // WEBASSEMBLY: extractelement <16 x i8> %v, i32 13 // WEBASSEMBLY-NEXT: zext @@ -215,7 +215,7 @@ int extract_lane_s_i16x8(i16x8 v) { // WEBASSEMBLY-NEXT: ret } -int extract_lane_u_i16x8(i16x8 v) { +int extract_lane_u_i16x8(u16x8 v) { return __builtin_wasm_extract_lane_u_i16x8(v, 7); // WEBASSEMBLY: extractelement <8 x i16> %v, i32 7 // WEBASSEMBLY-NEXT: zext @@ -291,7 +291,7 @@ i8x16 add_saturate_s_i8x16(i8x16 x, i8x16 y) { // WEBASSEMBLY-NEXT: ret } -i8x16 add_saturate_u_i8x16(i8x16 x, i8x16 y) { +u8x16 add_saturate_u_i8x16(u8x16 x, u8x16 y) { return __builtin_wasm_add_saturate_u_i8x16(x, y); // WEBASSEMBLY: call <16 x i8> @llvm.uadd.sat.v16i8( // WEBASSEMBLY-SAME: <16 x i8> %x, <16 x i8> %y) @@ -305,7 +305,7 @@ i16x8 add_saturate_s_i16x8(i16x8 x, i16x8 y) { // WEBASSEMBLY-NEXT: ret } -i16x8 add_saturate_u_i16x8(i16x8 x, i16x8 y) { +u16x8 add_saturate_u_i16x8(u16x8 x, u16x8 y) { return __builtin_wasm_add_saturate_u_i16x8(x, y); // WEBASSEMBLY: call <8 x i16> @llvm.uadd.sat.v8i16( // WEBASSEMBLY-SAME: <8 x i16> %x, <8 x i16> %y) @@ -319,7 +319,7 @@ i8x16 sub_saturate_s_i8x16(i8x16 x, i8x16 y) { // WEBASSEMBLY-NEXT: ret } -i8x16 sub_saturate_u_i8x16(i8x16 x, i8x16 y) { +u8x16 sub_saturate_u_i8x16(u8x16 x, u8x16 y) { return __builtin_wasm_sub_saturate_u_i8x16(x, y); // WEBASSEMBLY: call <16 x i8> @llvm.wasm.sub.saturate.unsigned.v16i8( // WEBASSEMBLY-SAME: <16 x i8> %x, <16 x i8> %y) @@ -357,7 +357,7 @@ i8x16 min_s_i8x16(i8x16 x, i8x16 y) { // WEBASSEMBLY-NEXT: ret <16 x i8> %1 } -i8x16 min_u_i8x16(i8x16 x, i8x16 y) { +u8x16 min_u_i8x16(u8x16 x, u8x16 y) { return __builtin_wasm_min_u_i8x16(x, y); // WEBASSEMBLY: %0 = icmp ult <16 x i8> %x, %y // WEBASSEMBLY-NEXT: %1 = select <16 x i1> %0, <16 x i8> %x, <16 x i8> %y @@ -371,7 +371,7 @@ i8x16 max_s_i8x16(i8x16 x, i8x16 y) { // WEBASSEMBLY-NEXT: ret <16 x i8> %1 } -i8x16 max_u_i8x16(i8x16 x, i8x16 y) { +u8x16 max_u_i8x16(u8x16 x, u8x16 y) { return __builtin_wasm_max_u_i8x16(x, y); // WEBASSEMBLY: %0 = icmp ugt <16 x i8> %x, %y // WEBASSEMBLY-NEXT: %1 = select <16 x i1> %0, <16 x i8> %x, <16 x i8> %y @@ -385,7 +385,7 @@ i16x8 min_s_i16x8(i16x8 x, i16x8 y) { // WEBASSEMBLY-NEXT: ret <8 x i16> %1 } -i16x8 min_u_i16x8(i16x8 x, i16x8 y) { +u16x8 min_u_i16x8(u16x8 x, u16x8 y) { return __builtin_wasm_min_u_i16x8(x, y); // WEBASSEMBLY: %0 = icmp ult <8 x i16> %x, %y // WEBASSEMBLY-NEXT: %1 = select <8 x i1> %0, <8 x i16> %x, <8 x i16> %y @@ -399,7 +399,7 @@ i16x8 max_s_i16x8(i16x8 x, i16x8 y) { // WEBASSEMBLY-NEXT: ret <8 x i16> %1 } -i16x8 max_u_i16x8(i16x8 x, i16x8 y) { +u16x8 max_u_i16x8(u16x8 x, u16x8 y) { return __builtin_wasm_max_u_i16x8(x, y); // WEBASSEMBLY: %0 = icmp ugt <8 x i16> %x, %y // WEBASSEMBLY-NEXT: %1 = select <8 x i1> %0, <8 x i16> %x, <8 x i16> %y @@ -413,7 +413,7 @@ i32x4 min_s_i32x4(i32x4 x, i32x4 y) { // WEBASSEMBLY-NEXT: ret <4 x i32> %1 } -i32x4 min_u_i32x4(i32x4 x, i32x4 y) { +u32x4 min_u_i32x4(u32x4 x, u32x4 y) { return __builtin_wasm_min_u_i32x4(x, y); // WEBASSEMBLY: %0 = icmp ult <4 x i32> %x, %y // WEBASSEMBLY-NEXT: %1 = select <4 x i1> %0, <4 x i32> %x, <4 x i32> %y @@ -427,7 +427,7 @@ i32x4 max_s_i32x4(i32x4 x, i32x4 y) { // WEBASSEMBLY-NEXT: ret <4 x i32> %1 } -i32x4 max_u_i32x4(i32x4 x, i32x4 y) { +u32x4 max_u_i32x4(u32x4 x, u32x4 y) { return __builtin_wasm_max_u_i32x4(x, y); // WEBASSEMBLY: %0 = icmp ugt <4 x i32> %x, %y // WEBASSEMBLY-NEXT: %1 = select <4 x i1> %0, <4 x i32> %x, <4 x i32> %y @@ -441,21 +441,21 @@ i16x8 sub_saturate_s_i16x8(i16x8 x, i16x8 y) { // WEBASSEMBLY-NEXT: ret } -i16x8 sub_saturate_u_i16x8(i16x8 x, i16x8 y) { +u16x8 sub_saturate_u_i16x8(u16x8 x, u16x8 y) { return __builtin_wasm_sub_saturate_u_i16x8(x, y); // WEBASSEMBLY: call <8 x i16> @llvm.wasm.sub.saturate.unsigned.v8i16( // WEBASSEMBLY-SAME: <8 x i16> %x, <8 x i16> %y) // WEBASSEMBLY-NEXT: ret } -i8x16 avgr_u_i8x16(i8x16 x, i8x16 y) { +u8x16 avgr_u_i8x16(u8x16 x, u8x16 y) { return __builtin_wasm_avgr_u_i8x16(x, y); // WEBASSEMBLY: call <16 x i8> @llvm.wasm.avgr.unsigned.v16i8( // WEBASSEMBLY-SAME: <16 x i8> %x, <16 x i8> %y) // WEBASSEMBLY-NEXT: ret } -i16x8 avgr_u_i16x8(i16x8 x, i16x8 y) { +u16x8 avgr_u_i16x8(u16x8 x, u16x8 y) { return __builtin_wasm_avgr_u_i16x8(x, y); // WEBASSEMBLY: call <8 x i16> @llvm.wasm.avgr.unsigned.v8i16( // WEBASSEMBLY-SAME: <8 x i16> %x, <8 x i16> %y) @@ -716,7 +716,7 @@ i8x16 narrow_s_i8x16_i16x8(i16x8 low, i16x8 high) { // WEBASSEMBLY: ret } -i8x16 narrow_u_i8x16_i16x8(i16x8 low, i16x8 high) { +u8x16 narrow_u_i8x16_i16x8(u16x8 low, u16x8 high) { return __builtin_wasm_narrow_u_i8x16_i16x8(low, high); // WEBASSEMBLY: call <16 x i8> @llvm.wasm.narrow.unsigned.v16i8.v8i16( // WEBASSEMBLY-SAME: <8 x i16> %low, <8 x i16> %high) @@ -730,13 +730,25 @@ i16x8 narrow_s_i16x8_i32x4(i32x4 low, i32x4 high) { // WEBASSEMBLY: ret } -i16x8 narrow_u_i16x8_i32x4(i32x4 low, i32x4 high) { +u16x8 narrow_u_i16x8_i32x4(u32x4 low, u32x4 high) { return __builtin_wasm_narrow_u_i16x8_i32x4(low, high); // WEBASSEMBLY: call <8 x i16> @llvm.wasm.narrow.unsigned.v8i16.v4i32( // WEBASSEMBLY-SAME: <4 x i32> %low, <4 x i32> %high) // WEBASSEMBLY: ret } +i32x4 load32_zero(int *p) { + return __builtin_wasm_load32_zero(p); + // WEBASSEMBLY: call <4 x i32> @llvm.wasm.load32.zero(i32* %p) + // WEBASSEMBLY: ret +} + +i64x2 load64_zero(long long *p) { + return __builtin_wasm_load64_zero(p); + // WEBASSEMBLY: call <2 x i64> @llvm.wasm.load64.zero(i64* %p) + // WEBASSEMBLY: ret +} + i8x16 swizzle_v8x16(i8x16 x, i8x16 y) { return __builtin_wasm_swizzle_v8x16(x, y); // WEBASSEMBLY: call <16 x i8> @llvm.wasm.swizzle(<16 x i8> %x, <16 x i8> %y) diff --git a/clang/test/CodeGen/callback_annotated.c b/clang/test/CodeGen/callback_annotated.c index c5b431d5ef845..83a79c3491daf 100644 --- a/clang/test/CodeGen/callback_annotated.c +++ b/clang/test/CodeGen/callback_annotated.c @@ -1,6 +1,4 @@ -// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 -fno-experimental-new-pass-manager %s -emit-llvm -o - | FileCheck %s --check-prefix=RUN1 -// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 -fno-experimental-new-pass-manager %s -emit-llvm -o - | FileCheck %s --check-prefix=RUN2 -// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 -fno-experimental-new-pass-manager %s -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -fno-experimental-new-pass-manager %s -emit-llvm -o - -disable-llvm-optzns | FileCheck %s --check-prefix=RUN1 // RUN1-DAG: @broker0({{[^#]*#[0-9]+}} !callback ![[cid0:[0-9]+]] __attribute__((callback(1, 2))) void *broker0(void *(*callee)(void *), void *payload) { @@ -29,22 +27,10 @@ __attribute__((callback(4, -1, a, __))) void *broker4(int a, int, int, int (*cal __attribute__((callback(4, d, 5, 2))) void *broker5(int, int, int, int (*callee)(int, int, int), int d); static void *VoidPtr2VoidPtr(void *payload) { - // RUN2: ret i8* %payload - // IPCP: ret i8* null return payload; } static int ThreeInt2Int(int a, int b, int c) { - // RUN2: define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c) - // RUN2: %mul = mul nsw i32 %b, %a - // RUN2: %add = add nsw i32 %mul, %c - // RUN2: ret i32 %add - - // IPCP: define internal i32 @ThreeInt2Int(i32 %a, i32 %b, i32 %c) - // IPCP: %mul = mul nsw i32 4, %a - // IPCP: %add = add nsw i32 %mul, %c - // IPCP: ret i32 %add - return a * b + c; } diff --git a/clang/test/CodeGen/callback_openmp.c b/clang/test/CodeGen/callback_openmp.c index 2fc9dcd391f63..90e63fdb2e580 100644 --- a/clang/test/CodeGen/callback_openmp.c +++ b/clang/test/CodeGen/callback_openmp.c @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp -O1 %s -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s +// RUN: %clang_cc1 -triple i386-unknown-unknown -fopenmp %s -emit-llvm -o - -disable-llvm-optzns | FileCheck %s // CHECK: declare !callback ![[cid:[0-9]+]] void @__kmpc_fork_call // CHECK: declare !callback ![[cid]] void @__kmpc_fork_teams @@ -15,14 +14,11 @@ void foo(int q) { #pragma omp parallel firstprivate(q, p) work1(p, q); -// IPCP: call void @work1(i32 2, i32 %{{[._a-zA-Z0-9]*}}) #pragma omp parallel for firstprivate(p, q) for (int i = 0; i < q; i++) work2(i, p); -// IPCP: call void @work2(i32 %{{[._a-zA-Z0-9]*}}, i32 2) #pragma omp target teams firstprivate(p) work12(p, p); -// IPCP: call void @work12(i32 2, i32 2) } diff --git a/clang/test/CodeGen/callback_pthread_create.c b/clang/test/CodeGen/callback_pthread_create.c index 785440030b32e..d1b01b91eac3f 100644 --- a/clang/test/CodeGen/callback_pthread_create.c +++ b/clang/test/CodeGen/callback_pthread_create.c @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -O1 %s -S -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -O1 %s -S -emit-llvm -o - | opt -ipconstprop -S | FileCheck --check-prefix=IPCP %s +// RUN: %clang_cc1 %s -S -emit-llvm -o - -disable-llvm-optzns | FileCheck %s // CHECK: declare !callback ![[cid:[0-9]+]] {{.*}}i32 @pthread_create // CHECK: ![[cid]] = !{![[cidb:[0-9]+]]} @@ -21,14 +20,10 @@ int pthread_create(pthread_t *, const pthread_attr_t *, const int GlobalVar = 0; static void *callee0(void *payload) { -// IPCP: define internal i8* @callee0 -// IPCP: ret i8* null return payload; } static void *callee1(void *payload) { -// IPCP: define internal i8* @callee1 -// IPCP: ret i8* bitcast (i32* @GlobalVar to i8*) return payload; } diff --git a/clang/test/CodeGen/ext-int.c b/clang/test/CodeGen/ext-int.c index 196bb810b61ab..d8e763283bfd9 100644 --- a/clang/test/CodeGen/ext-int.c +++ b/clang/test/CodeGen/ext-int.c @@ -45,3 +45,16 @@ void OffsetOfTest() { // LIN32: store i32 2097156, i32* %{{.+}} // WIN32: store i32 2097160, i32* %{{.+}} } + +void Size1ExtIntParam(unsigned _ExtInt(1) A) { + // CHECK: define {{.*}}void @Size1ExtIntParam(i1{{.*}} %[[PARAM:.+]]) + // CHECK: %[[PARAM_ADDR:.+]] = alloca i1 + // CHECK: %[[B:.+]] = alloca [5 x i1] + // CHECK: store i1 %[[PARAM]], i1* %[[PARAM_ADDR]] + unsigned _ExtInt(1) B[5]; + + // CHECK: %[[PARAM_LOAD:.+]] = load i1, i1* %[[PARAM_ADDR]] + // CHECK: %[[IDX:.+]] = getelementptr inbounds [5 x i1], [5 x i1]* %[[B]] + // CHECK: store i1 %[[PARAM_LOAD]], i1* %[[IDX]] + B[2] = A; +} diff --git a/clang/test/CodeGen/thinlto-distributed-newpm.ll b/clang/test/CodeGen/thinlto-distributed-newpm.ll index caf294df8eb85..9f9a8bec4ef5d 100644 --- a/clang/test/CodeGen/thinlto-distributed-newpm.ll +++ b/clang/test/CodeGen/thinlto-distributed-newpm.ll @@ -97,6 +97,7 @@ ; CHECK-O: Running pass: JumpThreadingPass on main ; CHECK-O: Running analysis: LazyValueAnalysis on main ; CHECK-O: Running pass: CorrelatedValuePropagationPass on main +; CHECK-O: Invalidating analysis: LazyValueAnalysis on main ; CHECK-O: Running pass: SimplifyCFGPass on main ; CHECK-O3: Running pass: AggressiveInstCombinePass on main ; CHECK-O: Running pass: InstCombinePass on main @@ -144,7 +145,6 @@ ; CHECK-O: Invalidating analysis: BasicAA on main ; CHECK-O: Invalidating analysis: AAManager on main ; CHECK-O: Invalidating analysis: MemorySSAAnalysis on main -; CHECK-O: Invalidating analysis: LazyValueAnalysis on main ; CHECK-O: Invalidating analysis: LoopAnalysis on main ; CHECK-O: Invalidating analysis: PhiValuesAnalysis on main ; CHECK-O: Invalidating analysis: MemoryDependenceAnalysis on main diff --git a/clang/test/CodeGen/ve-abi.c b/clang/test/CodeGen/ve-abi.c index aa35095d5dea0..1c230cb616a38 100644 --- a/clang/test/CodeGen/ve-abi.c +++ b/clang/test/CodeGen/ve-abi.c @@ -1,14 +1,96 @@ +/// Check that ABI is correctly implemented. +/// +/// 1. Check that all integer arguments and return values less than 64 bits +/// are sign/zero extended. +/// 2. Check that all complex arguments and return values are placed in +/// registers if it is possible. Not treat it as aggregate. +/// 3. Check that a function declared without argument type declarations is +/// treated as VARARGS (in order to place arguments in both registers and +/// memory locations in the back end) + // RUN: %clang_cc1 -triple ve-linux-gnu -emit-llvm %s -o - | FileCheck %s -// CHECK-LABEL: define { float, float } @p(float %a.coerce0, float %a.coerce1, float %b.coerce0, float %b.coerce1) #0 { -float __complex__ p(float __complex__ a, float __complex__ b) { +// CHECK-LABEL: define signext i8 @fun_si8(i8 signext %a, i8 signext %b) #0 { +char fun_si8(char a, char b) { + return a; +} + +// CHECK-LABEL: define zeroext i8 @fun_zi8(i8 zeroext %a, i8 zeroext %b) #0 { +unsigned char fun_zi8(unsigned char a, unsigned char b) { + return a; +} + +// CHECK-LABEL: define signext i16 @fun_si16(i16 signext %a, i16 signext %b) #0 { +short fun_si16(short a, short b) { + return a; +} + +// CHECK-LABEL: define zeroext i16 @fun_zi16(i16 zeroext %a, i16 zeroext %b) #0 { +unsigned short fun_zi16(unsigned short a, unsigned short b) { + return a; +} + +// CHECK-LABEL: define signext i32 @fun_si32(i32 signext %a, i32 signext %b) #0 { +int fun_si32(int a, int b) { + return a; +} + +// CHECK-LABEL: define zeroext i32 @fun_zi32(i32 zeroext %a, i32 zeroext %b) #0 { +unsigned int fun_zi32(unsigned int a, unsigned int b) { + return a; +} + +// CHECK-LABEL: define i64 @fun_si64(i64 %a, i64 %b) #0 { +long fun_si64(long a, long b) { + return a; +} + +// CHECK-LABEL: define i64 @fun_zi64(i64 %a, i64 %b) #0 { +unsigned long fun_zi64(unsigned long a, unsigned long b) { + return a; +} + +// CHECK-LABEL: define i128 @fun_si128(i128 %a, i128 %b) #0 { +__int128 fun_si128(__int128 a, __int128 b) { +} + +// CHECK-LABEL: define i128 @fun_zi128(i128 %a, i128 %b) #0 { +unsigned __int128 fun_zi128(unsigned __int128 a, unsigned __int128 b) { + return a; +} + +// CHECK-LABEL: define float @fun_float(float %a, float %b) #0 { +float fun_float(float a, float b) { + return a; +} + +// CHECK-LABEL: define double @fun_double(double %a, double %b) #0 { +double fun_double(double a, double b) { + return a; +} + +// CHECK-LABEL: define fp128 @fun_quad(fp128 %a, fp128 %b) #0 { +long double fun_quad(long double a, long double b) { + return a; +} + +// CHECK-LABEL: define { float, float } @fun_fcomplex(float %a.coerce0, float %a.coerce1, float %b.coerce0, float %b.coerce1) #0 { +float __complex__ fun_fcomplex(float __complex__ a, float __complex__ b) { + return a; +} + +// CHECK-LABEL: define { double, double } @fun_dcomplex(double %a.coerce0, double %a.coerce1, double %b.coerce0, double %b.coerce1) #0 { +double __complex__ fun_dcomplex(double __complex__ a, double __complex__ b) { + return a; } -// CHECK-LABEL: define { double, double } @q(double %a.coerce0, double %a.coerce1, double %b.coerce0, double %b.coerce1) #0 { -double __complex__ q(double __complex__ a, double __complex__ b) { +// CHECK-LABEL: define { fp128, fp128 } @fun_qcomplex(fp128 %a.coerce0, fp128 %a.coerce1, fp128 %b.coerce0, fp128 %b.coerce1) #0 { +long double __complex__ fun_qcomplex(long double __complex__ a, long double __complex__ b) { + return a; } +extern int hoge(); void func() { - // CHECK-LABEL: %call = call i32 (i32, i32, i32, i32, i32, i32, i32, ...) bitcast (i32 (...)* @hoge to i32 (i32, i32, i32, i32, i32, i32, i32, ...)*)(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7) + // CHECK: %call = call signext i32 (i32, i32, i32, i32, i32, i32, i32, ...) bitcast (i32 (...)* @hoge to i32 (i32, i32, i32, i32, i32, i32, i32, ...)*)(i32 signext 1, i32 signext 2, i32 signext 3, i32 signext 4, i32 signext 5, i32 signext 6, i32 signext 7) hoge(1, 2, 3, 4, 5, 6, 7); } diff --git a/clang/test/CodeGenCUDA/constexpr-variables.cu b/clang/test/CodeGenCUDA/constexpr-variables.cu index b8b0782b4f62f..7ae56341cdf57 100644 --- a/clang/test/CodeGenCUDA/constexpr-variables.cu +++ b/clang/test/CodeGenCUDA/constexpr-variables.cu @@ -19,7 +19,7 @@ struct Q { // CXX14: @_ZN1Q2k2E = {{.*}}externally_initialized constant i32 6 // CXX17: @_ZN1Q2k2E = internal {{.*}}constant i32 6 // CXX14: @_ZN1Q2k1E = available_externally {{.*}}constant i32 5 - // CXX17: @_ZN1Q2k1E = linkonce_odr {{.*}}constant i32 5 + // CXX17: @_ZN1Q2k1E = {{.*}} externally_initialized constant i32 5 static constexpr int k1 = 5; static constexpr int k2 = 6; }; @@ -30,14 +30,14 @@ __constant__ const int &use_Q_k2 = Q::k2; template struct X { // CXX14: @_ZN1XIiE1aE = available_externally {{.*}}constant i32 123 - // CXX17: @_ZN1XIiE1aE = linkonce_odr {{.*}}constant i32 123 + // CXX17: @_ZN1XIiE1aE = {{.*}}externally_initialized constant i32 123 static constexpr int a = 123; }; __constant__ const int &use_X_a = X::a; template struct A { // CXX14: @_ZN1AIiLi1ELi2EE1xE = available_externally {{.*}}constant i32 2 - // CXX17: @_ZN1AIiLi1ELi2EE1xE = linkonce_odr {{.*}}constant i32 2 + // CXX17: @_ZN1AIiLi1ELi2EE1xE = {{.*}}externally_initialized constant i32 2 constexpr static T x = a * b; }; __constant__ const int &y = A::x; diff --git a/clang/test/CodeGenCUDA/static-device-var-no-rdc.cu b/clang/test/CodeGenCUDA/static-device-var-no-rdc.cu new file mode 100644 index 0000000000000..1aea467c2d490 --- /dev/null +++ b/clang/test/CodeGenCUDA/static-device-var-no-rdc.cu @@ -0,0 +1,94 @@ +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fcuda-is-device \ +// RUN: -emit-llvm -o - -x hip %s | FileCheck \ +// RUN: -check-prefixes=DEV %s + +// RUN: %clang_cc1 -triple x86_64-gnu-linux \ +// RUN: -emit-llvm -o - -x hip %s | FileCheck \ +// RUN: -check-prefixes=HOST %s + +#include "Inputs/cuda.h" + +// Test function scope static device variable, which should not be externalized. +// DEV-DAG: @_ZZ6kernelPiPPKiE1w = internal addrspace(4) constant i32 1 + +// Check a static device variable referenced by host function is externalized. +// DEV-DAG: @_ZL1x = addrspace(1) externally_initialized global i32 0 +// HOST-DAG: @_ZL1x = internal global i32 undef +// HOST-DAG: @[[DEVNAMEX:[0-9]+]] = {{.*}}c"_ZL1x\00" + +static __device__ int x; + +// Check a static device variables referenced only by device functions and kernels +// is not externalized. +// DEV-DAG: @_ZL2x2 = internal addrspace(1) global i32 0 +static __device__ int x2; + +// Check a static device variable referenced by host device function is externalized. +// DEV-DAG: @_ZL2x3 = addrspace(1) externally_initialized global i32 0 +static __device__ int x3; + +// Check a static device variable referenced in file scope is externalized. +// DEV-DAG: @_ZL2x4 = addrspace(1) externally_initialized global i32 0 +static __device__ int x4; +int& x4_ref = x4; + +// Check a static device variable in anonymous namespace. +// DEV-DAG: @_ZN12_GLOBAL__N_12x5E = addrspace(1) externally_initialized global i32 0 +namespace { +static __device__ int x5; +} + +// Check a static constant variable referenced by host is externalized. +// DEV-DAG: @_ZL1y = addrspace(4) externally_initialized global i32 0 +// HOST-DAG: @_ZL1y = internal global i32 undef +// HOST-DAG: @[[DEVNAMEY:[0-9]+]] = {{.*}}c"_ZL1y\00" + +static __constant__ int y; + +// Test static host variable, which should not be externalized nor registered. +// HOST-DAG: @_ZL1z = internal global i32 0 +// DEV-NOT: @_ZL1z +static int z; + +// Test static device variable in inline function, which should not be +// externalized nor registered. +// DEV-DAG: @_ZZ6devfunPPKiE1p = linkonce_odr addrspace(4) constant i32 2, comdat + +inline __device__ void devfun(const int ** b) { + const static int p = 2; + b[0] = &p; + b[1] = &x2; +} + +__global__ void kernel(int *a, const int **b) { + const static int w = 1; + a[0] = x; + a[1] = y; + a[2] = x2; + a[3] = x3; + a[4] = x4; + a[5] = x5; + b[0] = &w; + devfun(b); +} + +__host__ __device__ void hdf(int *a) { + a[0] = x3; +} + +int* getDeviceSymbol(int *x); + +void foo(int *a) { + getDeviceSymbol(&x); + getDeviceSymbol(&x5); + getDeviceSymbol(&y); + z = 123; +} + +// HOST: __hipRegisterVar({{.*}}@_ZL1x {{.*}}@[[DEVNAMEX]] +// HOST: __hipRegisterVar({{.*}}@_ZL1y {{.*}}@[[DEVNAMEY]] +// HOST-NOT: __hipRegisterVar({{.*}}@_ZZ6kernelPiPPKiE1w +// HOST-NOT: __hipRegisterVar({{.*}}@_ZZ6devfunPPKiE1p diff --git a/clang/test/CodeGenCXX/fp16-mangle-arg-return.cpp b/clang/test/CodeGenCXX/fp16-mangle-arg-return.cpp new file mode 100644 index 0000000000000..15214e13ad8a7 --- /dev/null +++ b/clang/test/CodeGenCXX/fp16-mangle-arg-return.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple arm-arm-none-eabi -fallow-half-arguments-and-returns %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -o - -triple aarch64-arm-none-eabi -fallow-half-arguments-and-returns %s | FileCheck %s + +// Test name-mangling of __fp16 passed directly as a function argument +// (when that is permitted). + +// CHECK: define {{.*}}void @_Z13fp16_argumentDh(half %{{.*}}) +void fp16_argument(__fp16 arg) {} + +// Test name-mangling of __fp16 as a return type. The return type of +// fp16_return itself isn't mentioned in the mangled name, so to test +// this, we have to pass it a function pointer and make __fp16 the +// return type of that. + +// CHECK: define {{.*}}void @_Z11fp16_returnPFDhvE(half ()* %{{.*}}) +void fp16_return(__fp16 (*func)(void)) {} diff --git a/clang/test/CodeGenObjC/arc-unsafeclaim.m b/clang/test/CodeGenObjC/arc-unsafeclaim.m index a8011e024180d..40f1f164455a7 100644 --- a/clang/test/CodeGenObjC/arc-unsafeclaim.m +++ b/clang/test/CodeGenObjC/arc-unsafeclaim.m @@ -1,16 +1,16 @@ // Make sure it works on x86-64. -// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime=macosx-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED +// RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime=macosx-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=NOTAIL-CALL // Make sure it works on x86-32. -// RUN: %clang_cc1 -triple i386-apple-darwin11 -fobjc-runtime=macosx-fragile-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED +// RUN: %clang_cc1 -triple i386-apple-darwin11 -fobjc-runtime=macosx-fragile-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -check-prefix=CALL // Make sure it works on ARM. -// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED +// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -check-prefix=CALL +// RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED -check-prefix=CALL // Make sure it works on ARM64. -// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED +// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED -check-prefix=CALL +// RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED -check-prefix=CALL // Make sure that it's implicitly disabled if the runtime version isn't high enough. // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=DISABLED @@ -29,7 +29,8 @@ void test_assign() { // CHECK: [[T0:%.*]] = call [[A:.*]]* @makeA() // CHECK-MARKED-NEXT: call void asm sideeffect // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// NOTAIL-CALL-NEXT: [[T2:%.*]] = notail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// CALL-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* // CHECK-NEXT: store i8* [[T4]], i8** [[X]] @@ -53,7 +54,8 @@ void test_assign_assign() { // CHECK: [[T0:%.*]] = call [[A]]* @makeA() // CHECK-MARKED-NEXT: call void asm sideeffect // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// NOTAIL-CALL-NEXT: [[T2:%.*]] = notail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// CALL-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* // CHECK-NEXT: store i8* [[T4]], i8** [[Y]] @@ -126,7 +128,8 @@ void test_init() { // CHECK: [[T0:%.*]] = call [[A]]* @makeA() // CHECK-MARKED-NEXT: call void asm sideeffect // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// NOTAIL-CALL-NEXT: [[T2:%.*]] = notail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// CALL-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* // CHECK-NEXT: store i8* [[T4]], i8** [[X]] @@ -144,7 +147,8 @@ void test_init_assignment() { // CHECK: [[T0:%.*]] = call [[A]]* @makeA() // CHECK-MARKED-NEXT: call void asm sideeffect // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// NOTAIL-CALL-NEXT: [[T2:%.*]] = notail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// CALL-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* // CHECK-NEXT: store i8* [[T4]], i8** [[X]] @@ -212,7 +216,8 @@ void test_ignored() { // CHECK: [[T0:%.*]] = call [[A]]* @makeA() // CHECK-MARKED-NEXT: call void asm sideeffect // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// NOTAIL-CALL-NEXT: [[T2:%.*]] = notail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// CALL-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) // CHECK-NEXT: bitcast i8* [[T2]] to [[A]]* // CHECK-NEXT: ret void @@ -223,7 +228,8 @@ void test_cast_to_void() { // CHECK: [[T0:%.*]] = call [[A]]* @makeA() // CHECK-MARKED-NEXT: call void asm sideeffect // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* -// CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// NOTAIL-CALL-NEXT: [[T2:%.*]] = notail call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) +// CALL-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) // CHECK-NEXT: bitcast i8* [[T2]] to [[A]]* // CHECK-NEXT: ret void diff --git a/clang/test/CodeGenOpenCL/amdgpu-features.cl b/clang/test/CodeGenOpenCL/amdgpu-features.cl index 4c26163237980..93357a48eb89a 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-features.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-features.cl @@ -14,6 +14,7 @@ // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1011 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX1011 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1012 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX1012 %s // RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1030 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX1030 %s +// RUN: %clang_cc1 -triple amdgcn -target-cpu gfx1031 -S -emit-llvm -o - %s | FileCheck --check-prefix=GFX1031 %s // GFX600-NOT: "target-features" // GFX601-NOT: "target-features" @@ -26,5 +27,6 @@ // GFX1011: "target-features"="+16-bit-insts,+ci-insts,+dl-insts,+dot1-insts,+dot2-insts,+dot5-insts,+dot6-insts,+dpp,+flat-address-space,+gfx10-insts,+gfx8-insts,+gfx9-insts,+s-memrealtime" // GFX1012: "target-features"="+16-bit-insts,+ci-insts,+dl-insts,+dot1-insts,+dot2-insts,+dot5-insts,+dot6-insts,+dpp,+flat-address-space,+gfx10-insts,+gfx8-insts,+gfx9-insts,+s-memrealtime" // GFX1030: "target-features"="+16-bit-insts,+ci-insts,+dl-insts,+dot1-insts,+dot2-insts,+dot5-insts,+dot6-insts,+dpp,+flat-address-space,+gfx10-3-insts,+gfx10-insts,+gfx8-insts,+gfx9-insts,+s-memrealtime" +// GFX1031: "target-features"="+16-bit-insts,+ci-insts,+dl-insts,+dot1-insts,+dot2-insts,+dot5-insts,+dot6-insts,+dpp,+flat-address-space,+gfx10-3-insts,+gfx10-insts,+gfx8-insts,+gfx9-insts,+s-memrealtime" kernel void test() {} diff --git a/clang/test/CodeGenSYCL/template-template-parameter.cpp b/clang/test/CodeGenSYCL/template-template-parameter.cpp index 8c3f298d284ce..bda6d7a00e093 100644 --- a/clang/test/CodeGenSYCL/template-template-parameter.cpp +++ b/clang/test/CodeGenSYCL/template-template-parameter.cpp @@ -32,13 +32,13 @@ template void enqueue2() { template class Bar3; // CHECK: template class Bar3; template