diff --git a/.arclint b/.arclint new file mode 100644 index 0000000000000..01de1ee897ada --- /dev/null +++ b/.arclint @@ -0,0 +1,12 @@ +{ + "linters": { + "clang-format": { + "type": "script-and-regex", + "script-and-regex.script": "utils/arcanist/clang-format.sh", + "script-and-regex.regex": "/^(?P[[:alpha:]]+)\n(?P[^\n]+)\n(====|(?P\\d),(?P\\d)\n(?P.*)>>>>\n(?P.*)<<<<\n)$/s", + "include": [ + "(\\.(cc|cpp|h)$)" + ] + } + } +} diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 34d83b4381253..8c619d2a09632 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -187,7 +187,7 @@ void Info::mergeBase(Info &&Other) { // Unconditionally extend the description, since each decl may have a comment. std::move(Other.Description.begin(), Other.Description.end(), std::back_inserter(Description)); - std::sort(Description.begin(), Description.end()); + llvm::sort(Description); auto Last = std::unique(Description.begin(), Description.end()); Description.erase(Last, Description.end()); } @@ -202,7 +202,7 @@ void SymbolInfo::merge(SymbolInfo &&Other) { DefLoc = std::move(Other.DefLoc); // Unconditionally extend the list of locations, since we want all of them. std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc)); - std::sort(Loc.begin(), Loc.end()); + llvm::sort(Loc); auto Last = std::unique(Loc.begin(), Loc.end()); Loc.erase(Last, Loc.end()); mergeBase(std::move(Other)); @@ -314,7 +314,7 @@ bool Index::operator<(const Index &Other) const { } void Index::sort() { - std::sort(Children.begin(), Children.end()); + llvm::sort(Children); for (auto &C : Children) C.sort(); } diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 52c217b649f57..05594f191a5fb 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -454,7 +454,7 @@ std::vector ClangTidyASTConsumerFactory::getCheckNames() { CheckNames.push_back(AnalyzerCheckNamePrefix + AnalyzerCheck.first); #endif // CLANG_ENABLE_STATIC_ANALYZER - std::sort(CheckNames.begin(), CheckNames.end()); + llvm::sort(CheckNames); return CheckNames; } diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index 068d56c1a8a8f..2e30a3b403e85 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -124,7 +124,6 @@ ClangTidyError::ClangTidyError(StringRef CheckName, : tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory), IsWarningAsError(IsWarningAsError) {} - class ClangTidyContext::CachedGlobList { public: CachedGlobList(StringRef Globs) : Globs(Globs) {} @@ -297,57 +296,54 @@ static bool IsNOLINTFound(StringRef NolintDirectiveText, StringRef Line, return true; } +static llvm::Optional getBuffer(const SourceManager &SM, FileID File, + bool AllowIO) { + // This is similar to the implementation of SourceManager::getBufferData(), + // but uses ContentCache::getRawBuffer() rather than getBuffer() if + // AllowIO=false, to avoid triggering file I/O if the file contents aren't + // already mapped. + bool CharDataInvalid = false; + const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(File, &CharDataInvalid); + if (CharDataInvalid || !Entry.isFile()) + return llvm::None; + const SrcMgr::ContentCache *Cache = Entry.getFile().getContentCache(); + const llvm::MemoryBuffer *Buffer = + AllowIO ? Cache->getBuffer(SM.getDiagnostics(), SM.getFileManager(), + SourceLocation(), &CharDataInvalid) + : Cache->getRawBuffer(); + if (!Buffer || CharDataInvalid) + return llvm::None; + return Buffer->getBuffer(); +} + static bool LineIsMarkedWithNOLINT(const SourceManager &SM, SourceLocation Loc, unsigned DiagID, - const ClangTidyContext &Context) { - bool Invalid; - const char *CharacterData = SM.getCharacterData(Loc, &Invalid); - if (Invalid) + const ClangTidyContext &Context, + bool AllowIO) { + FileID File; + unsigned Offset; + std::tie(File, Offset) = SM.getDecomposedSpellingLoc(Loc); + llvm::Optional Buffer = getBuffer(SM, File, AllowIO); + if (!Buffer) return false; // Check if there's a NOLINT on this line. - const char *P = CharacterData; - while (*P != '\0' && *P != '\r' && *P != '\n') - ++P; - StringRef RestOfLine(CharacterData, P - CharacterData + 1); + StringRef RestOfLine = Buffer->substr(Offset).split('\n').first; if (IsNOLINTFound("NOLINT", RestOfLine, DiagID, Context)) return true; // Check if there's a NOLINTNEXTLINE on the previous line. - const char *BufBegin = - SM.getCharacterData(SM.getLocForStartOfFile(SM.getFileID(Loc)), &Invalid); - if (Invalid || P == BufBegin) - return false; - - // Scan backwards over the current line. - P = CharacterData; - while (P != BufBegin && *P != '\n') - --P; - - // If we reached the begin of the file there is no line before it. - if (P == BufBegin) - return false; - - // Skip over the newline. - --P; - const char *LineEnd = P; - - // Now we're on the previous line. Skip to the beginning of it. - while (P != BufBegin && *P != '\n') - --P; - - RestOfLine = StringRef(P, LineEnd - P + 1); - if (IsNOLINTFound("NOLINTNEXTLINE", RestOfLine, DiagID, Context)) - return true; - - return false; + StringRef PrevLine = + Buffer->substr(0, Offset).rsplit('\n').first.rsplit('\n').second; + return IsNOLINTFound("NOLINTNEXTLINE", PrevLine, DiagID, Context); } static bool LineIsMarkedWithNOLINTinMacro(const SourceManager &SM, SourceLocation Loc, unsigned DiagID, - const ClangTidyContext &Context) { + const ClangTidyContext &Context, + bool AllowIO) { while (true) { - if (LineIsMarkedWithNOLINT(SM, Loc, DiagID, Context)) + if (LineIsMarkedWithNOLINT(SM, Loc, DiagID, Context, AllowIO)) return true; if (!Loc.isMacroID()) return false; @@ -361,14 +357,13 @@ namespace tidy { bool shouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info, ClangTidyContext &Context, - bool CheckMacroExpansion) { + bool AllowIO) { return Info.getLocation().isValid() && DiagLevel != DiagnosticsEngine::Error && DiagLevel != DiagnosticsEngine::Fatal && - (CheckMacroExpansion ? LineIsMarkedWithNOLINTinMacro - : LineIsMarkedWithNOLINT)(Info.getSourceManager(), - Info.getLocation(), - Info.getID(), Context); + LineIsMarkedWithNOLINTinMacro(Info.getSourceManager(), + Info.getLocation(), Info.getID(), + Context, AllowIO); } } // namespace tidy @@ -680,7 +675,7 @@ void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { for (auto &FileAndEvents : FileEvents) { std::vector &Events = FileAndEvents.second; // Sweep. - std::sort(Events.begin(), Events.end()); + llvm::sort(Events); int OpenIntervals = 0; for (const auto &Event : Events) { if (Event.Type == Event::ET_End) @@ -710,9 +705,9 @@ struct LessClangTidyError { const tooling::DiagnosticMessage &M1 = LHS.Message; const tooling::DiagnosticMessage &M2 = RHS.Message; - return - std::tie(M1.FilePath, M1.FileOffset, LHS.DiagnosticName, M1.Message) < - std::tie(M2.FilePath, M2.FileOffset, RHS.DiagnosticName, M2.Message); + return std::tie(M1.FilePath, M1.FileOffset, LHS.DiagnosticName, + M1.Message) < + std::tie(M2.FilePath, M2.FileOffset, RHS.DiagnosticName, M2.Message); } }; struct EqualClangTidyError { @@ -726,7 +721,7 @@ struct EqualClangTidyError { std::vector ClangTidyDiagnosticConsumer::take() { finalizeLastError(); - std::sort(Errors.begin(), Errors.end(), LessClangTidyError()); + llvm::sort(Errors, LessClangTidyError()); Errors.erase(std::unique(Errors.begin(), Errors.end(), EqualClangTidyError()), Errors.end()); if (RemoveIncompatibleErrors) diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 18ce478805f8b..2bb3296b150dc 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -216,15 +216,12 @@ class ClangTidyContext { /// This does not handle suppression of notes following a suppressed diagnostic; /// that is left to the caller is it requires maintaining state in between calls /// to this function. -/// The `CheckMacroExpansion` parameter determines whether the function should -/// handle the case where the diagnostic is inside a macro expansion. A degree -/// of control over this is needed because handling this case can require -/// examining source files other than the one in which the diagnostic is -/// located, and in some use cases we cannot rely on such other files being -/// mapped in the SourceMapper. +/// If `AllowIO` is false, the function does not attempt to read source files +/// from disk which are not already mapped into memory; such files are treated +/// as not containing a suppression comment. bool shouldSuppressDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info, ClangTidyContext &Context, - bool CheckMacroExpansion = true); + bool AllowIO = true); /// A diagnostic consumer that turns each \c Diagnostic into a /// \c SourceManager-independent \c ClangTidyError. diff --git a/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp index cb275ab58f1be..04cc7aa9d4495 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp @@ -17,6 +17,12 @@ namespace clang { namespace tidy { namespace modernize { +namespace { +AST_MATCHER_P(InitListExpr, initCountIs, unsigned, N) { + return Node.getNumInits() == N; +} +} // namespace + static StringRef getValueOfValueInit(const QualType InitType) { switch (InitType->getScalarTypeKind()) { case Type::STK_CPointer: @@ -190,7 +196,7 @@ void UseDefaultMemberInitCheck::storeOptions( } void UseDefaultMemberInitCheck::registerMatchers(MatchFinder *Finder) { - auto Init = + auto InitBase = anyOf(stringLiteral(), characterLiteral(), integerLiteral(), unaryOperator(hasAnyOperatorName("+", "-"), hasUnaryOperand(integerLiteral())), @@ -198,7 +204,13 @@ void UseDefaultMemberInitCheck::registerMatchers(MatchFinder *Finder) { unaryOperator(hasAnyOperatorName("+", "-"), hasUnaryOperand(floatLiteral())), cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(), - initListExpr(), declRefExpr(to(enumConstantDecl()))); + declRefExpr(to(enumConstantDecl()))); + + auto Init = + anyOf(initListExpr(anyOf( + allOf(initCountIs(1), hasInit(0, ignoringImplicit(InitBase))), + initCountIs(0))), + InitBase); Finder->addMatcher( cxxConstructorDecl( diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp index 8975f294373c3..e41cdfcc08d8e 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp @@ -61,53 +61,8 @@ formatDereference(const ast_matchers::MatchFinder::MatchResult &Result, return (llvm::Twine("*") + Text).str(); } -// Trying to get CallExpr in which CxxConstructExpr is called. -static const clang::CallExpr * -tryGetCallExprAncestorForCxxConstructExpr(const Expr *TheExpr, - ASTContext &Context) { - // We skip nodes such as CXXBindTemporaryExpr, MaterializeTemporaryExpr. - for (ast_type_traits::DynTypedNode DynParent : Context.getParents(*TheExpr)) { - if (const auto *Parent = DynParent.get()) { - if (const auto *TheCallExpr = dyn_cast(Parent)) - return TheCallExpr; - - if (const clang::CallExpr *TheCallExpr = - tryGetCallExprAncestorForCxxConstructExpr(Parent, Context)) - return TheCallExpr; - } - } - - return nullptr; -} - -// Check that ParamDecl of CallExprDecl has rvalue type. -static bool checkParamDeclOfAncestorCallExprHasRValueRefType( - const Expr *TheCxxConstructExpr, ASTContext &Context) { - if (const clang::CallExpr *TheCallExpr = - tryGetCallExprAncestorForCxxConstructExpr(TheCxxConstructExpr, - Context)) { - for (unsigned i = 0; i < TheCallExpr->getNumArgs(); ++i) { - const Expr *Arg = TheCallExpr->getArg(i); - if (Arg->getSourceRange() == TheCxxConstructExpr->getSourceRange()) { - if (const auto *TheCallExprFuncProto = - TheCallExpr->getCallee() - ->getType() - ->getPointeeType() - ->getAs()) { - if (TheCallExprFuncProto->getParamType(i)->isRValueReferenceType()) - return true; - } - } - } - } - - return false; -} - -AST_MATCHER(CXXConstructExpr, - matchedParamDeclOfAncestorCallExprHasRValueRefType) { - return checkParamDeclOfAncestorCallExprHasRValueRefType( - &Node, Finder->getASTContext()); +AST_MATCHER(MaterializeTemporaryExpr, isBoundToLValue) { + return Node.isBoundToLvalueReference(); } } // end namespace @@ -141,11 +96,11 @@ void RedundantStringCStrCheck::registerMatchers( // Detect redundant 'c_str()' calls through a string constructor. // If CxxConstructExpr is the part of some CallExpr we need to // check that matched ParamDecl of the ancestor CallExpr is not rvalue. - Finder->addMatcher( - cxxConstructExpr( - StringConstructorExpr, hasArgument(0, StringCStrCallExpr), - unless(matchedParamDeclOfAncestorCallExprHasRValueRefType())), - this); + Finder->addMatcher(cxxConstructExpr(StringConstructorExpr, + hasArgument(0, StringCStrCallExpr), + unless(hasParent(materializeTemporaryExpr( + unless(isBoundToLValue()))))), + this); // Detect: 's == str.c_str()' -> 's == str' Finder->addMatcher( diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index d0e8d139a40e8..19476d7fa0522 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -150,21 +150,6 @@ llvm::Error validateEdits(const DraftStore &DraftMgr, const FileEdits &FE) { llvm::to_string(InvalidFileCount - 1) + " others)"); } -// Converts a list of Ranges to a LinkedList of SelectionRange. -SelectionRange render(const std::vector &Ranges) { - if (Ranges.empty()) - return {}; - SelectionRange Result; - Result.range = Ranges[0]; - auto *Next = &Result.parent; - for (const auto &R : llvm::make_range(Ranges.begin() + 1, Ranges.end())) { - *Next = std::make_unique(); - Next->get()->range = R; - Next = &Next->get()->parent; - } - return Result; -} - } // namespace // MessageHandler dispatches incoming LSP messages. @@ -473,6 +458,14 @@ void ClangdLSPServer::notify(llvm::StringRef Method, llvm::json::Value Params) { Transp.notify(Method, std::move(Params)); } +static std::vector semanticTokenTypes() { + std::vector Types; + for (unsigned I = 0; I <= static_cast(HighlightingKind::LastKind); + ++I) + Types.push_back(toSemanticTokenType(static_cast(I))); + return Types; +} + void ClangdLSPServer::onInitialize(const InitializeParams &Params, Callback Reply) { // Determine character encoding first as it affects constructed ClangdServer. @@ -487,6 +480,13 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, ClangdServerOpts.TheiaSemanticHighlighting = Params.capabilities.TheiaSemanticHighlighting; + if (Params.capabilities.TheiaSemanticHighlighting && + Params.capabilities.SemanticTokens) { + log("Client supports legacy semanticHighlights notification and standard " + "semanticTokens request, choosing the latter (no notifications)."); + ClangdServerOpts.TheiaSemanticHighlighting = false; + } + if (Params.rootUri && *Params.rootUri) ClangdServerOpts.WorkspaceRoot = std::string(Params.rootUri->file()); else if (Params.rootPath && !Params.rootPath->empty()) @@ -584,6 +584,14 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, // trigger on '->' and '::'. {"triggerCharacters", {".", ">", ":"}}, }}, + {"semanticTokensProvider", + llvm::json::Object{ + {"documentProvider", llvm::json::Object{{"edits", true}}}, + {"rangeProvider", false}, + {"legend", + llvm::json::Object{{"tokenTypes", semanticTokenTypes()}, + {"tokenModifiers", llvm::json::Array()}}}, + }}, {"signatureHelpProvider", llvm::json::Object{ {"triggerCharacters", {"(", ","}}, @@ -611,7 +619,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, }}}}; if (NegotiatedOffsetEncoding) Result["offsetEncoding"] = *NegotiatedOffsetEncoding; - if (Params.capabilities.TheiaSemanticHighlighting) + if (ClangdServerOpts.TheiaSemanticHighlighting) Result.getObject("capabilities") ->insert( {"semanticHighlighting", @@ -825,6 +833,10 @@ void ClangdLSPServer::onDocumentDidClose( std::lock_guard HLock(HighlightingsMutex); FileToHighlightings.erase(File); } + { + std::lock_guard HLock(SemanticTokensMutex); + LastSemanticTokens.erase(File); + } // clangd will not send updates for this file anymore, so we empty out the // list of diagnostics shown on the client (e.g. in the "Problems" pane of // VSCode). Note that this cannot race with actual diagnostics responses @@ -1206,24 +1218,13 @@ void ClangdLSPServer::onSymbolInfo(const TextDocumentPositionParams &Params, void ClangdLSPServer::onSelectionRange( const SelectionRangeParams &Params, Callback> Reply) { - if (Params.positions.size() != 1) { - elog("{0} positions provided to SelectionRange. Supports exactly one " - "position.", - Params.positions.size()); - return Reply(llvm::make_error( - "SelectionRange supports exactly one position", - ErrorCode::InvalidRequest)); - } Server->semanticRanges( - Params.textDocument.uri.file(), Params.positions[0], + Params.textDocument.uri.file(), Params.positions, [Reply = std::move(Reply)]( - llvm::Expected> Ranges) mutable { - if (!Ranges) { + llvm::Expected> Ranges) mutable { + if (!Ranges) return Reply(Ranges.takeError()); - } - std::vector Result; - Result.emplace_back(render(std::move(*Ranges))); - return Reply(std::move(Result)); + return Reply(std::move(*Ranges)); }); } @@ -1246,6 +1247,75 @@ void ClangdLSPServer::onDocumentLink( }); } +// Increment a numeric string: "" -> 1 -> 2 -> ... -> 9 -> 10 -> 11 ... +static void increment(std::string &S) { + for (char &C : llvm::reverse(S)) { + if (C != '9') { + ++C; + return; + } + C = '0'; + } + S.insert(S.begin(), '1'); +} + +void ClangdLSPServer::onSemanticTokens(const SemanticTokensParams &Params, + Callback CB) { + Server->semanticHighlights( + Params.textDocument.uri.file(), + [this, File(Params.textDocument.uri.file().str()), CB(std::move(CB))]( + llvm::Expected> HT) mutable { + if (!HT) + return CB(HT.takeError()); + SemanticTokens Result; + Result.tokens = toSemanticTokens(*HT); + { + std::lock_guard Lock(SemanticTokensMutex); + auto& Last = LastSemanticTokens[File]; + + Last.tokens = Result.tokens; + increment(Last.resultId); + Result.resultId = Last.resultId; + } + CB(std::move(Result)); + }); +} + +void ClangdLSPServer::onSemanticTokensEdits( + const SemanticTokensEditsParams &Params, + Callback CB) { + Server->semanticHighlights( + Params.textDocument.uri.file(), + [this, PrevResultID(Params.previousResultId), + File(Params.textDocument.uri.file().str()), CB(std::move(CB))]( + llvm::Expected> HT) mutable { + if (!HT) + return CB(HT.takeError()); + std::vector Toks = toSemanticTokens(*HT); + + SemanticTokensOrEdits Result; + { + std::lock_guard Lock(SemanticTokensMutex); + auto& Last = LastSemanticTokens[File]; + + if (PrevResultID == Last.resultId) { + Result.edits = diffTokens(Last.tokens, Toks); + } else { + vlog("semanticTokens/edits: wanted edits vs {0} but last result " + "had ID {1}. Returning full token list.", + PrevResultID, Last.resultId); + Result.tokens = Toks; + } + + Last.tokens = std::move(Toks); + increment(Last.resultId); + Result.resultId = Last.resultId; + } + + CB(std::move(Result)); + }); +} + ClangdLSPServer::ClangdLSPServer( class Transport &Transp, const FileSystemProvider &FSProvider, const clangd::CodeCompleteOptions &CCOpts, @@ -1293,6 +1363,8 @@ ClangdLSPServer::ClangdLSPServer( MsgHandler->bind("typeHierarchy/resolve", &ClangdLSPServer::onResolveTypeHierarchy); MsgHandler->bind("textDocument/selectionRange", &ClangdLSPServer::onSelectionRange); MsgHandler->bind("textDocument/documentLink", &ClangdLSPServer::onDocumentLink); + MsgHandler->bind("textDocument/semanticTokens", &ClangdLSPServer::onSemanticTokens); + MsgHandler->bind("textDocument/semanticTokens/edits", &ClangdLSPServer::onSemanticTokensEdits); // clang-format on } diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h index c4e9e5fb679c5..e259ad04a8e99 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -119,6 +119,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks { Callback>); void onDocumentLink(const DocumentLinkParams &, Callback>); + void onSemanticTokens(const SemanticTokensParams &, Callback); + void onSemanticTokensEdits(const SemanticTokensEditsParams &, + Callback); std::vector getFixes(StringRef File, const clangd::Diagnostic &D); @@ -161,6 +164,9 @@ class ClangdLSPServer : private ClangdServer::Callbacks { llvm::StringMap FixItsMap; std::mutex HighlightingsMutex; llvm::StringMap> FileToHighlightings; + // Last semantic-tokens response, for incremental requests. + std::mutex SemanticTokensMutex; + llvm::StringMap LastSemanticTokens; // Most code should not deal with Transport directly. // MessageHandler deals with incoming messages, use call() etc for outgoing. diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 3d68f85b6487d..c1773258554ce 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -134,7 +134,8 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB, : nullptr), GetClangTidyOptions(Opts.GetClangTidyOptions), SuggestMissingIncludes(Opts.SuggestMissingIncludes), - TweakFilter(Opts.TweakFilter), WorkspaceRoot(Opts.WorkspaceRoot), + BuildRecoveryAST(Opts.BuildRecoveryAST), TweakFilter(Opts.TweakFilter), + WorkspaceRoot(Opts.WorkspaceRoot), // Pass a callback into `WorkScheduler` to extract symbols from a newly // parsed file and rebuild the file index synchronously each time an AST // is parsed. @@ -191,6 +192,7 @@ void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents, Inputs.ForceRebuild = ForceRebuild; Inputs.Opts = std::move(Opts); Inputs.Index = Index; + Inputs.Opts.BuildRecoveryAST = BuildRecoveryAST; bool NewFile = WorkScheduler.update(File, Inputs, WantDiags); // If we loaded Foo.h, we want to make sure Foo.cpp is indexed. if (NewFile && BackgroundIdx) @@ -269,9 +271,13 @@ void ClangdServer::signatureHelp(PathRef File, Position Pos, if (!IP) return CB(IP.takeError()); - auto PreambleData = IP->Preamble; - CB(clangd::signatureHelp(File, IP->Command, PreambleData, IP->Contents, Pos, - FS, Index)); + const auto *PreambleData = IP->Preamble; + if (!PreambleData) + return CB(llvm::createStringError(llvm::inconvertibleErrorCode(), + "Failed to parse includes")); + + CB(clangd::signatureHelp(File, IP->Command, *PreambleData, IP->Contents, + Pos, FS, Index)); }; // Unlike code completion, we wait for an up-to-date preamble here. @@ -654,14 +660,22 @@ void ClangdServer::symbolInfo(PathRef File, Position Pos, WorkScheduler.runWithAST("SymbolInfo", File, std::move(Action)); } -void ClangdServer::semanticRanges(PathRef File, Position Pos, - Callback> CB) { - auto Action = - [Pos, CB = std::move(CB)](llvm::Expected InpAST) mutable { - if (!InpAST) - return CB(InpAST.takeError()); - CB(clangd::getSemanticRanges(InpAST->AST, Pos)); - }; +void ClangdServer::semanticRanges(PathRef File, + const std::vector &Positions, + Callback> CB) { + auto Action = [Positions, CB = std::move(CB)]( + llvm::Expected InpAST) mutable { + if (!InpAST) + return CB(InpAST.takeError()); + std::vector Result; + for (const auto &Pos : Positions) { + if (auto Range = clangd::getSemanticRanges(InpAST->AST, Pos)) + Result.push_back(std::move(*Range)); + else + return CB(Range.takeError()); + } + CB(std::move(Result)); + }; WorkScheduler.runWithAST("SemanticRanges", File, std::move(Action)); } @@ -677,6 +691,18 @@ void ClangdServer::documentLinks(PathRef File, TUScheduler::InvalidateOnUpdate); } +void ClangdServer::semanticHighlights( + PathRef File, Callback> CB) { + auto Action = + [CB = std::move(CB)](llvm::Expected InpAST) mutable { + if (!InpAST) + return CB(InpAST.takeError()); + CB(clangd::getSemanticHighlightings(InpAST->AST)); + }; + WorkScheduler.runWithAST("SemanticHighlights", File, std::move(Action), + TUScheduler::InvalidateOnUpdate); +} + std::vector> ClangdServer::getUsedBytesPerFile() const { return WorkScheduler.getUsedBytesPerFile(); diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index ae3dd8a065d8a..ae3da84c42c80 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -118,6 +118,9 @@ class ClangdServer { /// enabled. ClangTidyOptionsBuilder GetClangTidyOptions; + /// If true, turn on the `-frecovery-ast` clang flag. + bool BuildRecoveryAST = false; + /// Clangd's workspace root. Relevant for "workspace" operations not bound /// to a particular file. /// FIXME: If not set, should use the current working directory. @@ -142,7 +145,7 @@ class ClangdServer { /// fetch system include path. std::vector QueryDriverGlobs; - /// Enable semantic highlighting features. + /// Enable notification-based semantic highlighting. bool TheiaSemanticHighlighting = false; /// Returns true if the tweak should be enabled. @@ -292,12 +295,15 @@ class ClangdServer { Callback> CB); /// Get semantic ranges around a specified position in a file. - void semanticRanges(PathRef File, Position Pos, - Callback> CB); + void semanticRanges(PathRef File, const std::vector &Pos, + Callback> CB); /// Get all document links in a file. void documentLinks(PathRef File, Callback> CB); - + + void semanticHighlights(PathRef File, + Callback>); + /// Returns estimated memory usage for each of the currently open files. /// The order of results is unspecified. /// Overall memory usage of clangd may be significantly more than reported @@ -342,6 +348,9 @@ class ClangdServer { // can be caused by missing includes (e.g. member access in incomplete type). bool SuggestMissingIncludes = false; + // If true, preserve expressions in AST for broken code. + bool BuildRecoveryAST = false; + std::function TweakFilter; // GUARDED_BY(CachedCompletionFuzzyFindRequestMutex) diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 344b90ecaa320..b544510ecea10 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1022,7 +1022,7 @@ class SignatureHelpCollector final : public CodeCompleteConsumer { struct SemaCompleteInput { PathRef FileName; const tooling::CompileCommand &Command; - const PreambleData *Preamble; + const PreambleData &Preamble; llvm::StringRef Contents; size_t Offset; llvm::IntrusiveRefCntPtr VFS; @@ -1054,8 +1054,8 @@ bool semaCodeComplete(std::unique_ptr Consumer, IncludeStructure *Includes = nullptr) { trace::Span Tracer("Sema completion"); llvm::IntrusiveRefCntPtr VFS = Input.VFS; - if (Input.Preamble && Input.Preamble->StatCache) - VFS = Input.Preamble->StatCache->getConsumingFS(std::move(VFS)); + if (Input.Preamble.StatCache) + VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS)); ParseInputs ParseInput; ParseInput.CompileCommand = Input.Command; ParseInput.FS = VFS; @@ -1072,6 +1072,10 @@ bool semaCodeComplete(std::unique_ptr Consumer, FrontendOpts.SkipFunctionBodies = true; // Disable typo correction in Sema. CI->getLangOpts()->SpellChecking = false; + // Code completion won't trigger in delayed template bodies. + // This is on-by-default in windows to allow parsing SDK headers; we're only + // disabling it for the main-file (not preamble). + CI->getLangOpts()->DelayedTemplateParsing = false; // Setup code completion. FrontendOpts.CodeCompleteOpts = Options; FrontendOpts.CodeCompletionAt.FileName = std::string(Input.FileName); @@ -1095,9 +1099,7 @@ bool semaCodeComplete(std::unique_ptr Consumer, // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise // the remapped buffers do not get freed. auto Clang = prepareCompilerInstance( - std::move(CI), - (Input.Preamble && !CompletingInPreamble) ? &Input.Preamble->Preamble - : nullptr, + std::move(CI), !CompletingInPreamble ? &Input.Preamble.Preamble : nullptr, std::move(ContentsBuffer), std::move(VFS), IgnoreDiags); Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble; Clang->setCodeCompletionConsumer(Consumer.release()); @@ -1114,8 +1116,7 @@ bool semaCodeComplete(std::unique_ptr Consumer, // - but Sema code complete won't see them: as part of the preamble, they're // deserialized only when mentioned. // Force them to be deserialized so SemaCodeComplete sees them. - if (Input.Preamble) - loadMainFilePreambleMacros(Clang->getPreprocessor(), *Input.Preamble); + loadMainFilePreambleMacros(Clang->getPreprocessor(), Input.Preamble); if (Includes) Clang->getPreprocessor().addPPCallbacks( collectIncludeStructureCallback(Clang->getSourceManager(), Includes)); @@ -1754,12 +1755,12 @@ codeComplete(PathRef FileName, const tooling::CompileCommand &Command, return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse) ? std::move(Flow).runWithoutSema(Contents, *Offset, VFS) : std::move(Flow).run( - {FileName, Command, Preamble, Contents, *Offset, VFS}); + {FileName, Command, *Preamble, Contents, *Offset, VFS}); } SignatureHelp signatureHelp(PathRef FileName, const tooling::CompileCommand &Command, - const PreambleData *Preamble, + const PreambleData &Preamble, llvm::StringRef Contents, Position Pos, llvm::IntrusiveRefCntPtr VFS, const SymbolIndex *Index) { diff --git a/clang-tools-extra/clangd/CodeComplete.h b/clang-tools-extra/clangd/CodeComplete.h index df06c156049fb..3adea47c89a11 100644 --- a/clang-tools-extra/clangd/CodeComplete.h +++ b/clang-tools-extra/clangd/CodeComplete.h @@ -276,7 +276,7 @@ CodeCompleteResult codeComplete(PathRef FileName, /// Get signature help at a specified \p Pos in \p FileName. SignatureHelp signatureHelp(PathRef FileName, const tooling::CompileCommand &Command, - const PreambleData *Preamble, StringRef Contents, + const PreambleData &Preamble, StringRef Contents, Position Pos, IntrusiveRefCntPtr VFS, const SymbolIndex *Index); diff --git a/clang-tools-extra/clangd/Compiler.h b/clang-tools-extra/clangd/Compiler.h index ef5386bb0d17b..b7cc174455f31 100644 --- a/clang-tools-extra/clangd/Compiler.h +++ b/clang-tools-extra/clangd/Compiler.h @@ -38,6 +38,7 @@ class IgnoreDiagnostics : public DiagnosticConsumer { struct ParseOptions { tidy::ClangTidyOptions ClangTidyOpts; bool SuggestMissingIncludes = false; + bool BuildRecoveryAST = false; }; /// Information required to run clang, e.g. to parse AST or do code completion. diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 1d41f0a3e0461..63fe6b1d756c0 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -525,13 +525,13 @@ bool isParagraphLineBreak(llvm::StringRef Str, size_t LineBreakIndex) { return Str.substr(LineBreakIndex + 1) .drop_while([](auto C) { return C == ' ' || C == '\t'; }) .startswith("\n"); -}; +} bool isPunctuationLineBreak(llvm::StringRef Str, size_t LineBreakIndex) { constexpr llvm::StringLiteral Punctuation = R"txt(.:,;!?)txt"; return LineBreakIndex > 0 && Punctuation.contains(Str[LineBreakIndex - 1]); -}; +} bool isFollowedByHardLineBreakIndicator(llvm::StringRef Str, size_t LineBreakIndex) { @@ -556,7 +556,7 @@ bool isFollowedByHardLineBreakIndicator(llvm::StringRef Str, Str[NextNonSpaceCharIndex + 1] == ')'); return FollowedBySingleCharIndicator || FollowedByNumberedListIndicator; -}; +} bool isHardLineBreak(llvm::StringRef Str, size_t LineBreakIndex) { return isPunctuationLineBreak(Str, LineBreakIndex) || diff --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp index 91c71789dbe02..f6205879aa29c 100644 --- a/clang-tools-extra/clangd/ParsedAST.cpp +++ b/clang-tools-extra/clangd/ParsedAST.cpp @@ -253,6 +253,10 @@ ParsedAST::build(llvm::StringRef Version, const PrecompiledPreamble *PreamblePCH = Preamble ? &Preamble->Preamble : nullptr; + // Recovery expression currently only works for C++. + if (CI->getLangOpts()->CPlusPlus) + CI->getLangOpts()->RecoveryAST = Opts.BuildRecoveryAST; + StoreDiags ASTDiags; std::string Content = std::string(Buffer->getBuffer()); std::string Filename = @@ -310,14 +314,13 @@ ParsedAST::build(llvm::StringRef Version, // Check for suppression comment. Skip the check for diagnostics not // in the main file, because we don't want that function to query the // source buffer for preamble files. For the same reason, we ask - // shouldSuppressDiagnostic not to follow macro expansions, since - // those might take us into a preamble file as well. + // shouldSuppressDiagnostic to avoid I/O. bool IsInsideMainFile = Info.hasSourceManager() && isInsideMainFile(Info.getLocation(), Info.getSourceManager()); - if (IsInsideMainFile && tidy::shouldSuppressDiagnostic( - DiagLevel, Info, *CTContext, - /* CheckMacroExpansion = */ false)) { + if (IsInsideMainFile && + tidy::shouldSuppressDiagnostic(DiagLevel, Info, *CTContext, + /*AllowIO=*/false)) { return DiagnosticsEngine::Ignored; } } @@ -548,8 +551,7 @@ buildAST(PathRef FileName, std::unique_ptr Invocation, } return ParsedAST::build( - Inputs.Version, std::make_unique(*Invocation), - CompilerInvocationDiags, Preamble, + Inputs.Version, std::move(Invocation), CompilerInvocationDiags, Preamble, llvm::MemoryBuffer::getMemBufferCopy(Inputs.Contents, FileName), std::move(VFS), Inputs.Index, Inputs.Opts); } diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index fdee71fd22449..48f15420032fa 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -132,6 +132,10 @@ buildPreamble(PathRef FileName, CompilerInvocation &CI, // to read back. We rely on dynamic index for the comments instead. CI.getPreprocessorOpts().WriteCommentListToPCH = false; + // Recovery expression currently only works for C++. + if (CI.getLangOpts()->CPlusPlus) + CI.getLangOpts()->RecoveryAST = Inputs.Opts.BuildRecoveryAST; + CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback); if (Inputs.FS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) { log("Couldn't set working directory when building the preamble."); diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index 462aebc4b0465..cd8e6bc10dcef 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -297,6 +297,8 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R) { SemanticHighlighting->getBoolean("semanticHighlighting")) R.TheiaSemanticHighlighting = *SemanticHighlightingSupport; } + if (auto *SemanticHighlighting = TextDocument->getObject("semanticTokens")) + R.SemanticTokens = true; if (auto *Diagnostics = TextDocument->getObject("publishDiagnostics")) { if (auto CategorySupport = Diagnostics->getBoolean("categorySupport")) R.DiagnosticCategory = *CategorySupport; @@ -984,6 +986,59 @@ llvm::json::Value toJSON(const FileStatus &FStatus) { }; } +constexpr unsigned SemanticTokenEncodingSize = 5; +static llvm::json::Value encodeTokens(llvm::ArrayRef Toks) { + llvm::json::Array Result; + for (const auto &Tok : Toks) { + Result.push_back(Tok.deltaLine); + Result.push_back(Tok.deltaStart); + Result.push_back(Tok.length); + Result.push_back(Tok.tokenType); + Result.push_back(Tok.tokenModifiers); + } + assert(Result.size() == SemanticTokenEncodingSize * Toks.size()); + return Result; +} + +bool operator==(const SemanticToken &L, const SemanticToken &R) { + return std::tie(L.deltaLine, L.deltaStart, L.length, L.tokenType, + L.tokenModifiers) == std::tie(R.deltaLine, R.deltaStart, + R.length, R.tokenType, + R.tokenModifiers); +} + +llvm::json::Value toJSON(const SemanticTokens &Tokens) { + return llvm::json::Object{{"resultId", Tokens.resultId}, + {"data", encodeTokens(Tokens.tokens)}}; +} + +llvm::json::Value toJSON(const SemanticTokensEdit &Edit) { + return llvm::json::Object{ + {"start", SemanticTokenEncodingSize * Edit.startToken}, + {"deleteCount", SemanticTokenEncodingSize * Edit.deleteTokens}, + {"data", encodeTokens(Edit.tokens)}}; +} + +llvm::json::Value toJSON(const SemanticTokensOrEdits &TE) { + llvm::json::Object Result{{"resultId", TE.resultId}}; + if (TE.edits) + Result["edits"] = *TE.edits; + if (TE.tokens) + Result["data"] = encodeTokens(*TE.tokens); + return Result; +} + +bool fromJSON(const llvm::json::Value &Params, SemanticTokensParams &R) { + llvm::json::ObjectMapper O(Params); + return O && O.map("textDocument", R.textDocument); +} + +bool fromJSON(const llvm::json::Value &Params, SemanticTokensEditsParams &R) { + llvm::json::ObjectMapper O(Params); + return O && O.map("textDocument", R.textDocument) && + O.map("previousResultId", R.previousResultId); +} + llvm::raw_ostream &operator<<(llvm::raw_ostream &O, const DocumentHighlight &V) { O << V.range; diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index d08e546e3ffb2..968b039c62cca 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -433,8 +433,13 @@ struct ClientCapabilities { /// textDocument.codeAction.codeActionLiteralSupport. bool CodeActionStructure = false; + /// Client advertises support for the semanticTokens feature. + /// We support the textDocument/semanticTokens request in any case. + /// textDocument.semanticTokens + bool SemanticTokens = false; /// Client supports Theia semantic highlighting extension. /// https://github.com/microsoft/vscode-languageserver-node/pull/367 + /// This will be ignored if the client also supports semanticTokens. /// textDocument.semanticHighlightingCapabilities.semanticHighlighting /// FIXME: drop this support once clients support LSP 3.16 Semantic Tokens. bool TheiaSemanticHighlighting = false; @@ -1340,7 +1345,77 @@ struct FileStatus { std::string state; // FIXME: add detail messages. }; -llvm::json::Value toJSON(const FileStatus &FStatus); +llvm::json::Value toJSON(const FileStatus &); + +/// Specifies a single semantic token in the document. +/// This struct is not part of LSP, which just encodes lists of tokens as +/// arrays of numbers directly. +struct SemanticToken { + /// token line number, relative to the previous token + unsigned deltaLine = 0; + /// token start character, relative to the previous token + /// (relative to 0 or the previous token's start if they are on the same line) + unsigned deltaStart = 0; + /// the length of the token. A token cannot be multiline + unsigned length = 0; + /// will be looked up in `SemanticTokensLegend.tokenTypes` + unsigned tokenType = 0; + /// each set bit will be looked up in `SemanticTokensLegend.tokenModifiers` + unsigned tokenModifiers = 0; +}; +bool operator==(const SemanticToken &, const SemanticToken &); + +/// A versioned set of tokens. +struct SemanticTokens { + // An optional result id. If provided and clients support delta updating + // the client will include the result id in the next semantic token request. + // A server can then instead of computing all semantic tokens again simply + // send a delta. + std::string resultId; + + /// The actual tokens. For a detailed description about how the data is + /// structured pls see + /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 + std::vector tokens; +}; +llvm::json::Value toJSON(const SemanticTokens &); + +struct SemanticTokensParams { + /// The text document. + TextDocumentIdentifier textDocument; +}; +bool fromJSON(const llvm::json::Value &, SemanticTokensParams &); + +/// Requests the changes in semantic tokens since a previous response. +struct SemanticTokensEditsParams { + /// The text document. + TextDocumentIdentifier textDocument; + /// The previous result id. + std::string previousResultId; +}; +bool fromJSON(const llvm::json::Value &Params, SemanticTokensEditsParams &R); + +/// Describes a a replacement of a contiguous range of semanticTokens. +struct SemanticTokensEdit { + // LSP specifies `start` and `deleteCount` which are relative to the array + // encoding of the previous tokens. + // We use token counts instead, and translate when serializing this struct. + unsigned startToken = 0; + unsigned deleteTokens = 0; + std::vector tokens; +}; +llvm::json::Value toJSON(const SemanticTokensEdit &); + +/// This models LSP SemanticTokensEdits | SemanticTokens, which is the result of +/// textDocument/semanticTokens/edits. +struct SemanticTokensOrEdits { + std::string resultId; + /// Set if we computed edits relative to a previous set of tokens. + llvm::Optional> edits; + /// Set if we computed a fresh set of tokens. + llvm::Optional> tokens; +}; +llvm::json::Value toJSON(const SemanticTokensOrEdits &); /// Represents a semantic highlighting information that has to be applied on a /// specific line of the text document. diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index b69f9e8f2710e..35eabfe00dd24 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -445,6 +445,84 @@ bool operator==(const LineHighlightings &L, const LineHighlightings &R) { return std::tie(L.Line, L.Tokens) == std::tie(R.Line, R.Tokens); } +std::vector +toSemanticTokens(llvm::ArrayRef Tokens) { + assert(std::is_sorted(Tokens.begin(), Tokens.end())); + std::vector Result; + const HighlightingToken *Last = nullptr; + for (const HighlightingToken &Tok : Tokens) { + // FIXME: support inactive code - we need to provide the actual bounds. + if (Tok.Kind == HighlightingKind::InactiveCode) + continue; + Result.emplace_back(); + SemanticToken &Out = Result.back(); + // deltaStart/deltaLine are relative if possible. + if (Last) { + assert(Tok.R.start.line >= Last->R.start.line); + Out.deltaLine = Tok.R.start.line - Last->R.start.line; + if (Out.deltaLine == 0) { + assert(Tok.R.start.character >= Last->R.start.character); + Out.deltaStart = Tok.R.start.character - Last->R.start.character; + } else { + Out.deltaStart = Tok.R.start.character; + } + } else { + Out.deltaLine = Tok.R.start.line; + Out.deltaStart = Tok.R.start.character; + } + assert(Tok.R.end.line == Tok.R.start.line); + Out.length = Tok.R.end.character - Tok.R.start.character; + Out.tokenType = static_cast(Tok.Kind); + + Last = &Tok; + } + return Result; +} +llvm::StringRef toSemanticTokenType(HighlightingKind Kind) { + switch (Kind) { + case HighlightingKind::Variable: + case HighlightingKind::LocalVariable: + case HighlightingKind::StaticField: + return "variable"; + case HighlightingKind::Parameter: + return "parameter"; + case HighlightingKind::Function: + return "function"; + case HighlightingKind::Method: + return "member"; + case HighlightingKind::StaticMethod: + // FIXME: better function/member with static modifier? + return "function"; + case HighlightingKind::Field: + return "member"; + case HighlightingKind::Class: + return "class"; + case HighlightingKind::Enum: + return "enum"; + case HighlightingKind::EnumConstant: + return "enumConstant"; // nonstandard + case HighlightingKind::Typedef: + return "type"; + case HighlightingKind::DependentType: + return "dependent"; // nonstandard + case HighlightingKind::DependentName: + return "dependent"; // nonstandard + case HighlightingKind::Namespace: + return "namespace"; + case HighlightingKind::TemplateParameter: + return "typeParameter"; + case HighlightingKind::Concept: + return "concept"; // nonstandard + case HighlightingKind::Primitive: + return "type"; + case HighlightingKind::Macro: + return "macro"; + case HighlightingKind::InactiveCode: + return "comment"; + } + llvm_unreachable("unhandled HighlightingKind"); +} + std::vector toTheiaSemanticHighlightingInformation( llvm::ArrayRef Tokens) { @@ -522,5 +600,31 @@ llvm::StringRef toTextMateScope(HighlightingKind Kind) { llvm_unreachable("unhandled HighlightingKind"); } +std::vector +diffTokens(llvm::ArrayRef Old, + llvm::ArrayRef New) { + // For now, just replace everything from the first-last modification. + // FIXME: use a real diff instead, this is bad with include-insertion. + + unsigned Offset = 0; + while (!Old.empty() && !New.empty() && Old.front() == New.front()) { + ++Offset; + Old = Old.drop_front(); + New = New.drop_front(); + } + while (!Old.empty() && !New.empty() && Old.back() == New.back()) { + Old = Old.drop_back(); + New = New.drop_back(); + } + + if (Old.empty() && New.empty()) + return {}; + SemanticTokensEdit Edit; + Edit.startToken = Offset; + Edit.deleteTokens = Old.size(); + Edit.tokens = New; + return {std::move(Edit)}; +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/SemanticHighlighting.h b/clang-tools-extra/clangd/SemanticHighlighting.h index 31a97b81d6c24..9a96cc28c4f5e 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.h +++ b/clang-tools-extra/clangd/SemanticHighlighting.h @@ -6,8 +6,21 @@ // //===----------------------------------------------------------------------===// // -// An implementation of semantic highlighting based on this proposal: -// https://github.com/microsoft/vscode-languageserver-node/pull/367 in clangd. +// This file supports semantic highlighting: categorizing tokens in the file so +// that the editor can color/style them differently. +// +// This is particularly valuable for C++: its complex and context-dependent +// grammar is a challenge for simple syntax-highlighting techniques. +// +// We support two protocols for providing highlights to the client: +// - the `textDocument/semanticTokens` request from LSP 3.16 +// https://github.com/microsoft/vscode-languageserver-node/blob/release/protocol/3.16.0-next.1/protocol/src/protocol.semanticTokens.proposed.ts +// - the earlier proposed `textDocument/semanticHighlighting` notification +// https://github.com/microsoft/vscode-languageserver-node/pull/367 +// This is referred to as "Theia" semantic highlighting in the code. +// It was supported from clangd 9 but should be considered deprecated as of +// clangd 11 and eventually removed. +// // Semantic highlightings are calculated for an AST by visiting every AST node // and classifying nodes that are interesting to highlight (variables/function // calls etc.). @@ -75,6 +88,11 @@ bool operator==(const LineHighlightings &L, const LineHighlightings &R); // main AST. std::vector getSemanticHighlightings(ParsedAST &AST); +std::vector toSemanticTokens(llvm::ArrayRef); +llvm::StringRef toSemanticTokenType(HighlightingKind Kind); +std::vector diffTokens(llvm::ArrayRef Before, + llvm::ArrayRef After); + /// Converts a HighlightingKind to a corresponding TextMate scope /// (https://manual.macromates.com/en/language_grammars). llvm::StringRef toTextMateScope(HighlightingKind Kind); diff --git a/clang-tools-extra/clangd/SemanticSelection.cpp b/clang-tools-extra/clangd/SemanticSelection.cpp index 49fc7703db057..a6b1ebfb83275 100644 --- a/clang-tools-extra/clangd/SemanticSelection.cpp +++ b/clang-tools-extra/clangd/SemanticSelection.cpp @@ -12,6 +12,7 @@ #include "SourceCode.h" #include "clang/AST/DeclBase.h" #include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/Error.h" namespace clang { @@ -26,9 +27,8 @@ void addIfDistinct(const Range &R, std::vector &Result) { } } // namespace -llvm::Expected> getSemanticRanges(ParsedAST &AST, - Position Pos) { - std::vector Result; +llvm::Expected getSemanticRanges(ParsedAST &AST, Position Pos) { + std::vector Ranges; const auto &SM = AST.getSourceManager(); const auto &LangOpts = AST.getLangOpts(); @@ -56,9 +56,29 @@ llvm::Expected> getSemanticRanges(ParsedAST &AST, Range R; R.start = sourceLocToPosition(SM, SR->getBegin()); R.end = sourceLocToPosition(SM, SR->getEnd()); - addIfDistinct(R, Result); + addIfDistinct(R, Ranges); } - return Result; + + if (Ranges.empty()) { + // LSP provides no way to signal "the point is not within a semantic range". + // Return an empty range at the point. + SelectionRange Empty; + Empty.range.start = Empty.range.end = Pos; + return std::move(Empty); + } + + // Convert to the LSP linked-list representation. + SelectionRange Head; + Head.range = std::move(Ranges.front()); + SelectionRange *Tail = &Head; + for (auto &Range : + llvm::makeMutableArrayRef(Ranges.data(), Ranges.size()).drop_front()) { + Tail->parent = std::make_unique(); + Tail = Tail->parent.get(); + Tail->range = std::move(Range); + } + + return std::move(Head); } } // namespace clangd diff --git a/clang-tools-extra/clangd/SemanticSelection.h b/clang-tools-extra/clangd/SemanticSelection.h index b0d301e2efb89..810cc21d9a58f 100644 --- a/clang-tools-extra/clangd/SemanticSelection.h +++ b/clang-tools-extra/clangd/SemanticSelection.h @@ -22,10 +22,9 @@ namespace clangd { /// Returns the list of all interesting ranges around the Position \p Pos. /// The interesting ranges corresponds to the AST nodes in the SelectionTree /// containing \p Pos. -/// Any range in the result strictly contains all the previous ranges in the -/// result. front() is the inner most range. back() is the outermost range. -llvm::Expected> getSemanticRanges(ParsedAST &AST, - Position Pos); +/// If pos is not in any interesting range, return [Pos, Pos). +llvm::Expected getSemanticRanges(ParsedAST &AST, Position Pos); + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp index e5a001997ecc5..a2df2c3ff62f4 100644 --- a/clang-tools-extra/clangd/TUScheduler.cpp +++ b/clang-tools-extra/clangd/TUScheduler.cpp @@ -569,12 +569,10 @@ void ASTWorker::runWithAST( vlog("ASTWorker rebuilding evicted AST to run {0}: {1} version {2}", Name, FileName, CurrentInputs->Version); llvm::Optional NewAST = - Invocation - ? buildAST(FileName, - std::make_unique(*Invocation), - CompilerInvocationDiagConsumer.take(), *CurrentInputs, - getPossiblyStalePreamble()) - : None; + Invocation ? buildAST(FileName, std::move(Invocation), + CompilerInvocationDiagConsumer.take(), + *CurrentInputs, getPossiblyStalePreamble()) + : None; AST = NewAST ? std::make_unique(std::move(*NewAST)) : nullptr; } // Make sure we put the AST back into the LRU cache. diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 7d55a372905c0..2e2e6602c8d3e 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -43,6 +43,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -226,23 +227,21 @@ locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier, llvm::DenseMap ResultIndex; auto AddResultDecl = [&](const NamedDecl *D) { - const NamedDecl *Def = getDefinition(D); - const NamedDecl *Preferred = Def ? Def : D; - - auto Loc = makeLocation(AST.getASTContext(), nameLocation(*Preferred, SM), - MainFilePath); + D = llvm::cast(D->getCanonicalDecl()); + auto Loc = + makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath); if (!Loc) return; Result.emplace_back(); - Result.back().Name = printName(AST.getASTContext(), *Preferred); + Result.back().Name = printName(AST.getASTContext(), *D); Result.back().PreferredDeclaration = *Loc; - // Preferred is always a definition if possible, so this check works. - if (Def == Preferred) - Result.back().Definition = *Loc; + if (const NamedDecl *Def = getDefinition(D)) + Result.back().Definition = makeLocation( + AST.getASTContext(), nameLocation(*Def, SM), MainFilePath); // Record SymbolID for index lookup later. - if (auto ID = getSymbolID(Preferred)) + if (auto ID = getSymbolID(D)) ResultIndex[*ID] = Result.size() - 1; }; @@ -585,13 +584,11 @@ class ReferenceFinder : public index::IndexDataConsumer { SourceLocation Loc, index::IndexDataConsumer::ASTNodeInfo ASTNode) override { assert(D->isCanonicalDecl() && "expect D to be a canonical declaration"); - if (!CanonicalTargets.count(D)) + const SourceManager &SM = AST.getSourceManager(); + if (!CanonicalTargets.count(D) || !isInsideMainFile(Loc, SM)) return true; const auto &TB = AST.getTokens(); - const SourceManager &SM = AST.getSourceManager(); Loc = SM.getFileLoc(Loc); - // We are only traversing decls *inside* the main file, so this should hold. - assert(isInsideMainFile(Loc, SM)); if (const auto *Tok = TB.spelledTokenAt(Loc)) References.push_back({*Tok, Roles}); return true; diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/launch.json b/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/launch.json index cd6b87bd05c0a..7d414bc00f32e 100644 --- a/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/launch.json +++ b/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/launch.json @@ -1,4 +1,4 @@ -// A launch configuration that compiles the extension and then opens it inside a new window +// A launch configuration that compiles extension and opens it inside a new window. { "version": "0.1.0", "configurations": [ diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/tasks.json b/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/tasks.json index fb7f662e14d14..65b1c9598c0e1 100644 --- a/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/tasks.json +++ b/clang-tools-extra/clangd/clients/clangd-vscode/.vscode/tasks.json @@ -6,25 +6,27 @@ // ${fileExtname}: the current opened file's extension // ${cwd}: the current working directory of the spawned process -// A task runner that calls a custom npm script that compiles the extension. +// Task runner calls custom npm script to compile the extension. { - "version": "0.1.0", + "version": "2.0.0", - // we want to run npm + // Run NPM. "command": "npm", - // the command is a shell script - "isShellCommand": true, + // This command is a shell script. + "type": "shell", // show the output window only if unrecognized errors occur. - "showOutput": "silent", + "presentation": { + "reveal": "silent", + }, - // we run the custom script "compile" as defined in package.json + // Run custom "compile" script as defined in package.json "args": ["run", "compile", "--loglevel", "silent"], - // The tsc compiler is started in watching mode - "isWatching": true, + // tsc compiler is kept alive and runs in the background. + "isBackground": true, - // use the standard tsc in watch mode problem matcher to find compile problems in the output. + // Find compilation problems in the output through tsc in watch mode. "problemMatcher": "$tsc-watch" -} \ No newline at end of file +} diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/DEVELOPING.md b/clang-tools-extra/clangd/clients/clangd-vscode/DEVELOPING.md index e888aba3ea205..15f2b930329e9 100644 --- a/clang-tools-extra/clangd/clients/clangd-vscode/DEVELOPING.md +++ b/clang-tools-extra/clangd/clients/clangd-vscode/DEVELOPING.md @@ -10,20 +10,20 @@ A guide of developing `vscode-clangd` extension. ## Steps 1. Make sure you disable the installed `vscode-clangd` extension in VS Code. -2. Make sure you have clangd in /usr/bin/clangd or edit src/extension.ts to +2. Make sure you have clangd in `/usr/bin/clangd` or edit `src/extension.ts` to point to the binary. -3. In order to start a development instance of VS code extended with this, run: +3. To start a development instance of VS code extended with this, run: ```bash $ cd /path/to/clang-tools-extra/clangd/clients/clangd-vscode/ $ npm install $ code . - # When VS Code starts, press . + # When VSCode starts, press . ``` # Contributing -Please follow the exsiting code style when contributing to the extension, we +Please follow the existing code style when contributing to the extension, we recommend to run `npm run format` before sending a patch. # Publish to VS Code Marketplace @@ -38,15 +38,15 @@ to the marketplace. * Bump the version in `package.json`, and commit the change to upstream The extension is published under `llvm-vs-code-extensions` account, which is -currently maintained by clangd developers. If you want to make a new release, -please contact clangd-dev@lists.llvm.org. +maintained by clangd developers. If you want to make a new release, please +contact clangd-dev@lists.llvm.org. ## Steps ```bash $ cd /path/to/clang-tools-extra/clangd/clients/clangd-vscode/ - # For the first time, you need to login in the account. vsce will ask you for - the Personal Access Token, and remember it for future commands. + # For the first time, you need to login into the account. vsce will ask you + for the Personal Access Token and will remember it for future commands. $ vsce login llvm-vs-code-extensions # Publish the extension to the VSCode marketplace. $ npm run publish diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts b/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts index 4749cd1bb5820..a7570b63e552e 100644 --- a/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts +++ b/clang-tools-extra/clangd/clients/clangd-vscode/src/extension.ts @@ -3,7 +3,7 @@ import * as vscodelc from 'vscode-languageclient'; import * as semanticHighlighting from './semantic-highlighting'; /** - * Method to get workspace configuration option + * Get an option from workspace configuration. * @param option name of the option (e.g. for clangd.path should be path) * @param defaultValue default value to return if option is not set */ @@ -75,8 +75,8 @@ class EnableEditsNearCursorFeature implements vscodelc.StaticFeature { } /** - * this method is called when your extension is activate - * your extension is activated the very first time the command is executed + * This method is called when the extension is activated. The extension is + * activated the very first time a command is executed. */ export function activate(context: vscode.ExtensionContext) { const syncFileEvents = getConfig('syncFileEvents', true); @@ -97,7 +97,7 @@ export function activate(context: vscode.ExtensionContext) { documentSelector: [ { scheme: 'file', language: 'c' }, { scheme: 'file', language: 'cpp' }, - // cuda is not supported by vscode, but our extension does. + // CUDA is not supported by vscode, but our extension does supports it. { scheme: 'file', language: 'cuda' }, { scheme: 'file', language: 'objective-c'}, { scheme: 'file', language: 'objective-cpp'} @@ -106,7 +106,7 @@ export function activate(context: vscode.ExtensionContext) { // FIXME: send sync file events when clangd provides implementations. }, initializationOptions: { clangdFileStatus: true }, - // Do not switch to output window when clangd returns output + // Do not switch to output window when clangd returns output. revealOutputChannelOn: vscodelc.RevealOutputChannelOn.Never, // We hack up the completion items a bit to prevent VSCode from re-ranking them @@ -126,7 +126,7 @@ export function activate(context: vscode.ExtensionContext) { provideCompletionItem: async (document, position, context, token, next) => { let list = await next(document, position, context, token); let items = (Array.isArray(list) ? list : list.items).map(item => { - // Gets the prefix used by vscode when doing fuzzymatch. + // Gets the prefix used by VSCode when doing fuzzymatch. let prefix = document.getText(new vscode.Range(item.range.start, position)) if (prefix) item.filterText = prefix + "_" + item.filterText; diff --git a/clang-tools-extra/clangd/clients/clangd-vscode/tsconfig.json b/clang-tools-extra/clangd/clients/clangd-vscode/tsconfig.json index 0b05f3090920a..71a62c71da025 100644 --- a/clang-tools-extra/clangd/clients/clangd-vscode/tsconfig.json +++ b/clang-tools-extra/clangd/clients/clangd-vscode/tsconfig.json @@ -26,4 +26,4 @@ "node_modules", ".vscode-test" ] -} \ No newline at end of file +} diff --git a/clang-tools-extra/clangd/index/Relation.cpp b/clang-tools-extra/clangd/index/Relation.cpp index e28591bb64b00..6daa10a6f95ea 100644 --- a/clang-tools-extra/clangd/index/Relation.cpp +++ b/clang-tools-extra/clangd/index/Relation.cpp @@ -26,7 +26,7 @@ RelationSlab::lookup(const SymbolID &Subject, RelationKind Predicate) const { RelationSlab RelationSlab::Builder::build() && { // Sort in SPO order. - std::sort(Relations.begin(), Relations.end()); + llvm::sort(Relations); // Remove duplicates. Relations.erase(std::unique(Relations.begin(), Relations.end()), diff --git a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp new file mode 100644 index 0000000000000..1ecec6674b022 --- /dev/null +++ b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp @@ -0,0 +1,286 @@ +//===--- AddUsing.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 "AST.h" +#include "FindTarget.h" +#include "Logger.h" +#include "refactor/Tweak.h" +#include "clang/AST/Decl.h" +#include "clang/AST/RecursiveASTVisitor.h" + +namespace clang { +namespace clangd { +namespace { + +// Tweak for removing full namespace qualifier under cursor on DeclRefExpr and +// types and adding "using" statement instead. +// +// Only qualifiers that refer exclusively to namespaces (no record types) are +// supported. There is some guessing of appropriate place to insert the using +// declaration. If we find any existing usings, we insert it there. If not, we +// insert right after the inner-most relevant namespace declaration. If there is +// none, or there is, but it was declared via macro, we insert above the first +// top level decl. +// +// Currently this only removes qualifier from under the cursor. In the future, +// we should improve this to remove qualifier from all occurences of this +// symbol. +class AddUsing : public Tweak { +public: + const char *id() const override; + + bool prepare(const Selection &Inputs) override; + Expected apply(const Selection &Inputs) override; + std::string title() const override; + Intent intent() const override { return Refactor; } + +private: + // The qualifier to remove. Set by prepare(). + NestedNameSpecifierLoc QualifierToRemove; + // The name following QualifierToRemove. Set by prepare(). + llvm::StringRef Name; +}; +REGISTER_TWEAK(AddUsing) + +std::string AddUsing::title() const { + return std::string(llvm::formatv( + "Add using-declaration for {0} and remove qualifier.", Name)); +} + +// Locates all "using" statements relevant to SelectionDeclContext. +class UsingFinder : public RecursiveASTVisitor { +public: + UsingFinder(std::vector &Results, + const DeclContext *SelectionDeclContext, const SourceManager &SM) + : Results(Results), SelectionDeclContext(SelectionDeclContext), SM(SM) {} + + bool VisitUsingDecl(UsingDecl *D) { + auto Loc = D->getUsingLoc(); + if (SM.getFileID(Loc) != SM.getMainFileID()) { + return true; + } + if (D->getDeclContext()->Encloses(SelectionDeclContext)) { + Results.push_back(D); + } + return true; + } + + bool TraverseDecl(Decl *Node) { + // There is no need to go deeper into nodes that do not enclose selection, + // since "using" there will not affect selection, nor would it make a good + // insertion point. + if (Node->getDeclContext()->Encloses(SelectionDeclContext)) { + return RecursiveASTVisitor::TraverseDecl(Node); + } + return true; + } + +private: + std::vector &Results; + const DeclContext *SelectionDeclContext; + const SourceManager &SM; +}; + +struct InsertionPointData { + // Location to insert the "using" statement. If invalid then the statement + // should not be inserted at all (it already exists). + SourceLocation Loc; + // Extra suffix to place after the "using" statement. Depending on what the + // insertion point is anchored to, we may need one or more \n to ensure + // proper formatting. + std::string Suffix; +}; + +// Finds the best place to insert the "using" statement. Returns invalid +// SourceLocation if the "using" statement already exists. +// +// The insertion point might be a little awkward if the decl we're anchoring to +// has a comment in an unfortunate place (e.g. directly above function or using +// decl, or immediately following "namespace {". We should add some helpers for +// dealing with that and use them in other code modifications as well. +llvm::Expected +findInsertionPoint(const Tweak::Selection &Inputs, + const NestedNameSpecifierLoc &QualifierToRemove, + const llvm::StringRef Name) { + auto &SM = Inputs.AST->getSourceManager(); + + // Search for all using decls that affect this point in file. We need this for + // two reasons: to skip adding "using" if one already exists and to find best + // place to add it, if it doesn't exist. + SourceLocation LastUsingLoc; + std::vector Usings; + UsingFinder(Usings, &Inputs.ASTSelection.commonAncestor()->getDeclContext(), + SM) + .TraverseAST(Inputs.AST->getASTContext()); + + for (auto &U : Usings) { + if (SM.isBeforeInTranslationUnit(Inputs.Cursor, U->getUsingLoc())) + // "Usings" is sorted, so we're done. + break; + if (U->getQualifier()->getAsNamespace()->getCanonicalDecl() == + QualifierToRemove.getNestedNameSpecifier() + ->getAsNamespace() + ->getCanonicalDecl() && + U->getName() == Name) { + return InsertionPointData(); + } + // Insertion point will be before last UsingDecl that affects cursor + // position. For most cases this should stick with the local convention of + // add using inside or outside namespace. + LastUsingLoc = U->getUsingLoc(); + } + if (LastUsingLoc.isValid()) { + InsertionPointData Out; + Out.Loc = LastUsingLoc; + return Out; + } + + // No relevant "using" statements. Try the nearest namespace level. + const auto *NS = Inputs.ASTSelection.commonAncestor() + ->getDeclContext() + .getEnclosingNamespaceContext(); + if (auto *ND = dyn_cast(NS)) { + auto Toks = Inputs.AST->getTokens().expandedTokens(ND->getSourceRange()); + const auto *Tok = llvm::find_if(Toks, [](const syntax::Token &Tok) { + return Tok.kind() == tok::l_brace; + }); + if (Tok == Toks.end() || Tok->endLocation().isInvalid()) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Namespace with no {"); + } + if (!Tok->endLocation().isMacroID()) { + InsertionPointData Out; + Out.Loc = Tok->endLocation(); + Out.Suffix = "\n"; + return Out; + } + } + // No using, no namespace, no idea where to insert. Try above the first + // top level decl. + auto TLDs = Inputs.AST->getLocalTopLevelDecls(); + if (TLDs.empty()) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Cannot find place to insert \"using\""); + } + InsertionPointData Out; + Out.Loc = SM.getExpansionLoc(TLDs[0]->getBeginLoc()); + Out.Suffix = "\n\n"; + return Out; +} + +bool AddUsing::prepare(const Selection &Inputs) { + auto &SM = Inputs.AST->getSourceManager(); + auto *Node = Inputs.ASTSelection.commonAncestor(); + if (Node == nullptr) + return false; + + // If we're looking at a type or NestedNameSpecifier, walk up the tree until + // we find the "main" node we care about, which would be ElaboratedTypeLoc or + // DeclRefExpr. + for (; Node->Parent; Node = Node->Parent) { + if (Node->ASTNode.get()) { + continue; + } else if (auto *T = Node->ASTNode.get()) { + if (T->getAs()) { + break; + } else if (Node->Parent->ASTNode.get() || + Node->Parent->ASTNode.get()) { + // Node is TypeLoc, but it's parent is either TypeLoc or + // NestedNameSpecifier. In both cases, we want to go up, to find + // the outermost TypeLoc. + continue; + } + } + break; + } + if (Node == nullptr) + return false; + + if (auto *D = Node->ASTNode.get()) { + QualifierToRemove = D->getQualifierLoc(); + Name = D->getDecl()->getName(); + } else if (auto *T = Node->ASTNode.get()) { + if (auto E = T->getAs()) { + QualifierToRemove = E.getQualifierLoc(); + Name = + E.getType().getUnqualifiedType().getBaseTypeIdentifier()->getName(); + } + } + + // FIXME: This only supports removing qualifiers that are made up of just + // namespace names. If qualifier contains a type, we could take the longest + // namespace prefix and remove that. + if (!QualifierToRemove.hasQualifier() || + !QualifierToRemove.getNestedNameSpecifier()->getAsNamespace() || + Name.empty()) { + return false; + } + + // Macros are difficult. We only want to offer code action when what's spelled + // under the cursor is a namespace qualifier. If it's a macro that expands to + // a qualifier, user would not know what code action will actually change. + // On the other hand, if the qualifier is part of the macro argument, we + // should still support that. + if (SM.isMacroBodyExpansion(QualifierToRemove.getBeginLoc()) || + !SM.isWrittenInSameFile(QualifierToRemove.getBeginLoc(), + QualifierToRemove.getEndLoc())) { + return false; + } + + return true; +} + +Expected AddUsing::apply(const Selection &Inputs) { + auto &SM = Inputs.AST->getSourceManager(); + auto &TB = Inputs.AST->getTokens(); + + // Determine the length of the qualifier under the cursor, then remove it. + auto SpelledTokens = TB.spelledForExpanded( + TB.expandedTokens(QualifierToRemove.getSourceRange())); + if (!SpelledTokens) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Could not determine length of the qualifier"); + } + unsigned Length = + syntax::Token::range(SM, SpelledTokens->front(), SpelledTokens->back()) + .length(); + tooling::Replacements R; + if (auto Err = R.add(tooling::Replacement( + SM, SpelledTokens->front().location(), Length, ""))) { + return std::move(Err); + } + + auto InsertionPoint = findInsertionPoint(Inputs, QualifierToRemove, Name); + if (!InsertionPoint) { + return InsertionPoint.takeError(); + } + + if (InsertionPoint->Loc.isValid()) { + // Add the using statement at appropriate location. + std::string UsingText; + llvm::raw_string_ostream UsingTextStream(UsingText); + UsingTextStream << "using "; + QualifierToRemove.getNestedNameSpecifier()->print( + UsingTextStream, Inputs.AST->getASTContext().getPrintingPolicy()); + UsingTextStream << Name << ";" << InsertionPoint->Suffix; + + assert(SM.getFileID(InsertionPoint->Loc) == SM.getMainFileID()); + if (auto Err = R.add(tooling::Replacement(SM, InsertionPoint->Loc, 0, + UsingTextStream.str()))) { + return std::move(Err); + } + } + + return Effect::mainFileEdit(Inputs.AST->getASTContext().getSourceManager(), + std::move(R)); +} + +} // namespace +} // namespace clangd +} // namespace clang diff --git a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt index 5817830b7ea37..995288bca2cf4 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt +++ b/clang-tools-extra/clangd/refactor/tweaks/CMakeLists.txt @@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS # $ to a list of sources, see # clangd/tool/CMakeLists.txt for an example. add_clang_library(clangDaemonTweaks OBJECT + AddUsing.cpp AnnotateHighlightings.cpp DumpAST.cpp DefineInline.cpp diff --git a/clang-tools-extra/clangd/test/initialize-params.test b/clang-tools-extra/clangd/test/initialize-params.test index 2b5c02fc8ce28..6c4b847a07ef2 100644 --- a/clang-tools-extra/clangd/test/initialize-params.test +++ b/clang-tools-extra/clangd/test/initialize-params.test @@ -38,6 +38,18 @@ # CHECK-NEXT: "referencesProvider": true, # CHECK-NEXT: "renameProvider": true, # CHECK-NEXT: "selectionRangeProvider": true, +# CHECK-NEXT: "semanticTokensProvider": { +# CHECK-NEXT: "documentProvider": { +# CHECK-NEXT: "edits": true +# CHECK-NEXT: }, +# CHECK-NEXT: "legend": { +# CHECK-NEXT: "tokenModifiers": [], +# CHECK-NEXT: "tokenTypes": [ +# CHECK-NEXT: "variable", +# CHECK: ] +# CHECK-NEXT: }, +# CHECK-NEXT: "rangeProvider": false +# CHECK-NEXT: }, # CHECK-NEXT: "signatureHelpProvider": { # CHECK-NEXT: "triggerCharacters": [ # CHECK-NEXT: "(", diff --git a/clang-tools-extra/clangd/test/semantic-tokens.test b/clang-tools-extra/clangd/test/semantic-tokens.test new file mode 100644 index 0000000000000..6fab10362b285 --- /dev/null +++ b/clang-tools-extra/clangd/test/semantic-tokens.test @@ -0,0 +1,87 @@ +# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s -implicit-check-not=semanticHighlight +# Send capabilities for both Theia semanticHighlight & standard semanticTokens. +# clangd should not use/acknowledge the Theia protocol in this case. +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"capabilities":{"textDocument":{ + "semanticHighlightingCapabilities":{"semanticHighlighting":true}, + "semanticTokens":{"dynamicRegistration":true} +}}}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{ + "uri": "test:///foo.cpp", + "languageId": "cpp", + "text": "int x = 2;" +}}} +--- +# Non-incremental token request. +{"jsonrpc":"2.0","id":1,"method":"textDocument/semanticTokens","params":{"textDocument":{"uri":"test:///foo.cpp"}}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "data": [ +# First line, char 5, variable, no modifiers. +# CHECK-NEXT: 0, +# CHECK-NEXT: 4, +# CHECK-NEXT: 1, +# CHECK-NEXT: 0, +# CHECK-NEXT: 0 +# CHECK-NEXT: ], +# CHECK-NEXT: "resultId": "1" +# CHECK-NEXT: } +--- +{"jsonrpc":"2.0","method":"textDocument/didChange","params":{ + "textDocument": {"uri":"test:///foo.cpp","version":2}, + "contentChanges":[{"text":"int x = 2;\nint y = 3;"}] +}} +--- +# Incremental token request, based on previous response. +{"jsonrpc":"2.0","id":2,"method":"textDocument/semanticTokens/edits","params":{ + "textDocument": {"uri":"test:///foo.cpp"}, + "previousResultId": "1" +}} +# CHECK: "id": 2, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "edits": [ +# CHECK-NEXT: { +# CHECK-NEXT: "data": [ +# Next line, char 5, variable, no modifiers +# CHECK-NEXT: 1, +# CHECK-NEXT: 4, +# CHECK-NEXT: 1, +# CHECK-NEXT: 0, +# CHECK-NEXT: 0 +# CHECK-NEXT: ], +# Inserted at position 1 +# CHECK-NEXT: "deleteCount": 0, +# CHECK-NEXT: "start": 5 +# CHECK-NEXT: } +# CHECK-NEXT: ], +# CHECK-NEXT: "resultId": "2" +# CHECK-NEXT: } +--- +# Incremental token request with incorrect baseline => full tokens list. +{"jsonrpc":"2.0","id":2,"method":"textDocument/semanticTokens/edits","params":{ + "textDocument": {"uri":"test:///foo.cpp"}, + "previousResultId": "bogus" +}} +# CHECK: "id": 2, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "data": [ +# CHECK-NEXT: 0, +# CHECK-NEXT: 4, +# CHECK-NEXT: 1, +# CHECK-NEXT: 0, +# CHECK-NEXT: 0, +# CHECK-NEXT: 1, +# CHECK-NEXT: 4, +# CHECK-NEXT: 1, +# CHECK-NEXT: 0, +# CHECK-NEXT: 0 +# CHECK-NEXT: ], +# CHECK-NEXT: "resultId": "3" +# CHECK-NEXT: } +--- +{"jsonrpc":"2.0","id":3,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 7a7bb9b0718e0..4b3b565ac2b6d 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -281,6 +281,15 @@ opt CrossFileRename{ Hidden, }; +opt RecoveryAST{ + "recovery-ast", + cat(Features), + desc("Preserve expressions in AST for broken code (C++ only). Note that " + "this feature is experimental and may lead to crashes"), + init(false), + Hidden, +}; + opt WorkerThreadsCount{ "j", cat(Misc), @@ -629,6 +638,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var } Opts.StaticIndex = StaticIdx.get(); Opts.AsyncThreadsCount = WorkerThreadsCount; + Opts.BuildRecoveryAST = RecoveryAST; clangd::CodeCompleteOptions CCOpts; CCOpts.IncludeIneligibleResults = IncludeIneligibleResults; @@ -681,18 +691,42 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var std::unique_ptr ClangTidyOptProvider; /*GUARDED_BY(ClangTidyOptMu)*/ if (EnableClangTidy) { - auto OverrideClangTidyOptions = tidy::ClangTidyOptions::getDefaults(); - OverrideClangTidyOptions.Checks = ClangTidyChecks; + auto EmptyDefaults = tidy::ClangTidyOptions::getDefaults(); + EmptyDefaults.Checks.reset(); // So we can tell if checks were ever set. + tidy::ClangTidyOptions OverrideClangTidyOptions; + if (!ClangTidyChecks.empty()) + OverrideClangTidyOptions.Checks = ClangTidyChecks; ClangTidyOptProvider = std::make_unique( tidy::ClangTidyGlobalOptions(), - /* Default */ tidy::ClangTidyOptions::getDefaults(), + /* Default */ EmptyDefaults, /* Override */ OverrideClangTidyOptions, FSProvider.getFileSystem()); Opts.GetClangTidyOptions = [&](llvm::vfs::FileSystem &, llvm::StringRef File) { // This function must be thread-safe and tidy option providers are not. - std::lock_guard Lock(ClangTidyOptMu); - // FIXME: use the FS provided to the function. - return ClangTidyOptProvider->getOptions(File); + tidy::ClangTidyOptions Opts; + { + std::lock_guard Lock(ClangTidyOptMu); + // FIXME: use the FS provided to the function. + Opts = ClangTidyOptProvider->getOptions(File); + } + if (!Opts.Checks) { + // If the user hasn't configured clang-tidy checks at all, including + // via .clang-tidy, give them a nice set of checks. + // (This should be what the "default" options does, but it isn't...) + // + // These default checks are chosen for: + // - low false-positive rate + // - providing a lot of value + // - being reasonably efficient + Opts.Checks = llvm::join_items( + ",", "readability-misleading-indentation", + "readability-deleted-default", "bugprone-integer-division", + "bugprone-sizeof-expression", "bugprone-suspicious-missing-comma", + "bugprone-unused-raii", "bugprone-unused-return-value", + "misc-unused-using-decls", "misc-unused-alias-decls", + "misc-definitions-in-headers"); + } + return Opts; }; } Opts.SuggestMissingIncludes = SuggestMissingIncludes; diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp index 1e5fcf3d97e1a..d15eba80ae29e 100644 --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -552,15 +552,13 @@ TEST_F(ClangdVFSTest, InvalidCompileCommand) { EXPECT_ERROR(runFindDocumentHighlights(Server, FooCpp, Position())); EXPECT_ERROR(runRename(Server, FooCpp, Position(), "new_name", clangd::RenameOptions())); + EXPECT_ERROR(runSignatureHelp(Server, FooCpp, Position())); // Identifier-based fallback completion. EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Position(), clangd::CodeCompleteOptions())) .Completions, ElementsAre(Field(&CodeCompletion::Name, "int"), Field(&CodeCompletion::Name, "main"))); - auto SigHelp = runSignatureHelp(Server, FooCpp, Position()); - ASSERT_TRUE(bool(SigHelp)) << "signatureHelp returned an error"; - EXPECT_THAT(SigHelp->signatures, IsEmpty()); } class ClangdThreadingTest : public ClangdVFSTest {}; diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index f5c90a4677cb8..1084b15505799 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -93,8 +93,9 @@ std::unique_ptr memIndex(std::vector Symbols) { return MemIndex::build(std::move(Slab).build(), RefSlab(), RelationSlab()); } -CodeCompleteResult completions(ClangdServer &Server, llvm::StringRef TestCode, - Position Point, +// Runs code completion. +// If IndexSymbols is non-empty, an index will be built and passed to opts. +CodeCompleteResult completions(const TestTU &TU, Position Point, std::vector IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}) { std::unique_ptr OverrideIndex; @@ -104,49 +105,34 @@ CodeCompleteResult completions(ClangdServer &Server, llvm::StringRef TestCode, Opts.Index = OverrideIndex.get(); } - auto File = testPath("foo.cpp"); - runAddDocument(Server, File, TestCode); - auto CompletionList = - llvm::cantFail(runCodeComplete(Server, File, Point, Opts)); - return CompletionList; -} - -CodeCompleteResult completions(ClangdServer &Server, llvm::StringRef Text, - std::vector IndexSymbols = {}, - clangd::CodeCompleteOptions Opts = {}, - PathRef FilePath = "foo.cpp") { - std::unique_ptr OverrideIndex; - if (!IndexSymbols.empty()) { - assert(!Opts.Index && "both Index and IndexSymbols given!"); - OverrideIndex = memIndex(std::move(IndexSymbols)); - Opts.Index = OverrideIndex.get(); + auto Inputs = TU.inputs(); + IgnoreDiagnostics Diags; + auto CI = buildCompilerInvocation(Inputs, Diags); + if (!CI) { + ADD_FAILURE() << "Couldn't build CompilerInvocation"; + return {}; } - - auto File = testPath(FilePath); - Annotations Test(Text); - runAddDocument(Server, File, Test.code()); - auto CompletionList = - llvm::cantFail(runCodeComplete(Server, File, Test.point(), Opts)); - return CompletionList; + auto Preamble = + buildPreamble(testPath(TU.Filename), *CI, /*OldPreamble=*/nullptr, Inputs, + /*InMemory=*/true, /*Callback=*/nullptr); + return codeComplete(testPath(TU.Filename), Inputs.CompileCommand, + Preamble.get(), TU.Code, Point, Inputs.FS, Opts); } -// Builds a server and runs code completion. -// If IndexSymbols is non-empty, an index will be built and passed to opts. +// Runs code completion. CodeCompleteResult completions(llvm::StringRef Text, std::vector IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}, PathRef FilePath = "foo.cpp") { - MockFSProvider FS; - MockCompilationDatabase CDB; + Annotations Test(Text); + auto TU = TestTU::withCode(Test.code()); // To make sure our tests for completiopns inside templates work on Windows. - CDB.ExtraClangFlags = {"-fno-delayed-template-parsing"}; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); - return completions(Server, Text, std::move(IndexSymbols), std::move(Opts), - FilePath); + TU.Filename = FilePath.str(); + return completions(TU, Test.point(), std::move(IndexSymbols), + std::move(Opts)); } -// Builds a server and runs code completion. -// If IndexSymbols is non-empty, an index will be built and passed to opts. +// Runs code completion without the clang parser. CodeCompleteResult completionsNoCompile(llvm::StringRef Text, std::vector IndexSymbols = {}, clangd::CodeCompleteOptions Opts = {}, @@ -669,53 +655,38 @@ TEST(CompletionTest, SemaIndexMergeWithLimit) { } TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) { - MockFSProvider FS; - MockCompilationDatabase CDB; - std::string Subdir = testPath("sub"); - std::string SearchDirArg = (Twine("-I") + Subdir).str(); - CDB.ExtraClangFlags = {SearchDirArg.c_str()}; - std::string BarHeader = testPath("sub/bar.h"); - FS.Files[BarHeader] = ""; + TestTU TU; + TU.ExtraArgs.push_back("-I" + testPath("sub")); + TU.AdditionalFiles["sub/bar.h"] = ""; + auto BarURI = URI::create(testPath("sub/bar.h")).toString(); - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); - auto BarURI = URI::create(BarHeader).toString(); Symbol Sym = cls("ns::X"); Sym.CanonicalDeclaration.FileURI = BarURI.c_str(); Sym.IncludeHeaders.emplace_back(BarURI, 1); // Shoten include path based on search directory and insert. - auto Results = completions(Server, - R"cpp( - int main() { ns::^ } - )cpp", - {Sym}); + Annotations Test("int main() { ns::^ }"); + TU.Code = Test.code().str(); + auto Results = completions(TU, Test.point(), {Sym}); EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), InsertInclude("\"bar.h\"")))); // Can be disabled via option. CodeCompleteOptions NoInsertion; NoInsertion.InsertIncludes = CodeCompleteOptions::NeverInsert; - Results = completions(Server, - R"cpp( - int main() { ns::^ } - )cpp", - {Sym}, NoInsertion); + Results = completions(TU, Test.point(), {Sym}, NoInsertion); EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), Not(InsertInclude())))); // Duplicate based on inclusions in preamble. - Results = completions(Server, - R"cpp( + Test = Annotations(R"cpp( #include "sub/bar.h" // not shortest, so should only match resolved. int main() { ns::^ } - )cpp", - {Sym}); + )cpp"); + TU.Code = Test.code().str(); + Results = completions(TU, Test.point(), {Sym}); EXPECT_THAT(Results.Completions, ElementsAre(AllOf(Named("X"), Labeled("X"), Not(InsertInclude())))); } TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) { - MockFSProvider FS; - MockCompilationDatabase CDB; - - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); Symbol SymX = cls("ns::X"); Symbol SymY = cls("ns::Y"); std::string BarHeader = testPath("bar.h"); @@ -725,8 +696,7 @@ TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) { SymX.IncludeHeaders.emplace_back("", 1); SymY.IncludeHeaders.emplace_back("", 1); // Shoten include path based on search directory and insert. - auto Results = completions(Server, - R"cpp( + auto Results = completions(R"cpp( namespace ns { class X; class Y {}; @@ -740,34 +710,27 @@ TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) { } TEST(CompletionTest, IndexSuppressesPreambleCompletions) { - MockFSProvider FS; - MockCompilationDatabase CDB; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); - - FS.Files[testPath("bar.h")] = - R"cpp(namespace ns { struct preamble { int member; }; })cpp"; - auto File = testPath("foo.cpp"); Annotations Test(R"cpp( #include "bar.h" namespace ns { int local; } void f() { ns::^; } void f2() { ns::preamble().$2^; } )cpp"); - runAddDocument(Server, File, Test.code()); - clangd::CodeCompleteOptions Opts = {}; + auto TU = TestTU::withCode(Test.code()); + TU.AdditionalFiles["bar.h"] = + R"cpp(namespace ns { struct preamble { int member; }; })cpp"; + clangd::CodeCompleteOptions Opts = {}; auto I = memIndex({var("ns::index")}); Opts.Index = I.get(); - auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts)); + auto WithIndex = completions(TU, Test.point(), {}, Opts); EXPECT_THAT(WithIndex.Completions, UnorderedElementsAre(Named("local"), Named("index"))); - auto ClassFromPreamble = - cantFail(runCodeComplete(Server, File, Test.point("2"), Opts)); + auto ClassFromPreamble = completions(TU, Test.point("2"), {}, Opts); EXPECT_THAT(ClassFromPreamble.Completions, Contains(Named("member"))); Opts.Index = nullptr; - auto WithoutIndex = - cantFail(runCodeComplete(Server, File, Test.point(), Opts)); + auto WithoutIndex = completions(TU, Test.point(), {}, Opts); EXPECT_THAT(WithoutIndex.Completions, UnorderedElementsAre(Named("local"), Named("preamble"))); } @@ -811,7 +774,14 @@ TEST(CompletionTest, DynamicIndexIncludeInsertion) { Server.addDocument(testPath("foo_impl.cpp"), FileContent); // Wait for the dynamic index being built. ASSERT_TRUE(Server.blockUntilIdleForTest()); - EXPECT_THAT(completions(Server, "Foo^ foo;").Completions, + + auto File = testPath("foo.cpp"); + Annotations Test("Foo^ foo;"); + runAddDocument(Server, File, Test.code()); + auto CompletionList = + llvm::cantFail(runCodeComplete(Server, File, Test.point(), {})); + + EXPECT_THAT(CompletionList.Completions, ElementsAre(AllOf(Named("Foo"), HasInclude("\"foo_header.h\""), InsertInclude()))); } @@ -892,13 +862,17 @@ TEST(CompletionTest, CommentsFromSystemHeaders) { int foo(); )cpp"; - auto Results = completions(Server, - R"cpp( + auto File = testPath("foo.cpp"); + Annotations Test(R"cpp( #include "foo.h" int x = foo^ )cpp"); + runAddDocument(Server, File, Test.code()); + auto CompletionList = + llvm::cantFail(runCodeComplete(Server, File, Test.point(), {})); + EXPECT_THAT( - Results.Completions, + CompletionList.Completions, Contains(AllOf(Named("foo"), Doc("This comment should be retained!")))); } @@ -1064,15 +1038,23 @@ SignatureHelp signatures(llvm::StringRef Text, Position Point, if (!IndexSymbols.empty()) Index = memIndex(IndexSymbols); - MockFSProvider FS; - MockCompilationDatabase CDB; - ClangdServer::Options Opts = ClangdServer::optsForTest(); - Opts.StaticIndex = Index.get(); - - ClangdServer Server(CDB, FS, Opts); - auto File = testPath("foo.cpp"); - runAddDocument(Server, File, Text); - return llvm::cantFail(runSignatureHelp(Server, File, Point)); + auto TU = TestTU::withCode(Text); + auto Inputs = TU.inputs(); + IgnoreDiagnostics Diags; + auto CI = buildCompilerInvocation(Inputs, Diags); + if (!CI) { + ADD_FAILURE() << "Couldn't build CompilerInvocation"; + return {}; + } + auto Preamble = + buildPreamble(testPath(TU.Filename), *CI, /*OldPreamble=*/nullptr, Inputs, + /*InMemory=*/true, /*Callback=*/nullptr); + if (!Preamble) { + ADD_FAILURE() << "Couldn't build Preamble"; + return {}; + } + return signatureHelp(testPath(TU.Filename), Inputs.CompileCommand, *Preamble, + Text, Point, Inputs.FS, Index.get()); } SignatureHelp signatures(llvm::StringRef Text, @@ -1195,9 +1177,7 @@ TEST(SignatureHelpTest, OpeningParen) { int foo(int a, int b, int c); int main() { #define ID(X) X - // FIXME: figure out why ID(foo (foo(10), )) doesn't work when preserving - // the recovery expression. - ID(foo $p^( 10, ^ )) + ID(foo $p^( foo(10), ^ )) })cpp"}; for (auto Test : Tests) { @@ -1548,14 +1528,7 @@ TEST(CompletionTest, DocumentationFromChangedFileCrash) { } TEST(CompletionTest, NonDocComments) { - MockFSProvider FS; - auto FooCpp = testPath("foo.cpp"); - FS.Files[FooCpp] = ""; - - MockCompilationDatabase CDB; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); - - Annotations Source(R"cpp( + const char *Text = R"cpp( // We ignore namespace comments, for rationale see CodeCompletionStrings.h. namespace comments_ns { } @@ -1590,17 +1563,11 @@ TEST(CompletionTest, NonDocComments) { int Struct::comments_quux() { int a = comments^; } - )cpp"); - // FIXME: Auto-completion in a template requires disabling delayed template - // parsing. - CDB.ExtraClangFlags.push_back("-fno-delayed-template-parsing"); - runAddDocument(Server, FooCpp, Source.code(), "null", WantDiagnostics::Yes); - CodeCompleteResult Completions = cantFail(runCodeComplete( - Server, FooCpp, Source.point(), clangd::CodeCompleteOptions())); + )cpp"; // We should not get any of those comments in completion. EXPECT_THAT( - Completions.Completions, + completions(Text).Completions, UnorderedElementsAre(AllOf(Not(IsDocumented()), Named("comments_foo")), AllOf(IsDocumented(), Named("comments_baz")), AllOf(IsDocumented(), Named("comments_quux")), @@ -1742,11 +1709,10 @@ TEST(CompletionTest, CodeCompletionContext) { TEST(CompletionTest, FixItForArrowToDot) { MockFSProvider FS; MockCompilationDatabase CDB; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); CodeCompleteOptions Opts; Opts.IncludeFixIts = true; - Annotations TestCode( + const char* Code = R"cpp( class Auxilary { public: @@ -1762,13 +1728,12 @@ TEST(CompletionTest, FixItForArrowToDot) { ClassWithPtr x; x[[->]]^; } - )cpp"); - auto Results = - completions(Server, TestCode.code(), TestCode.point(), {}, Opts); + )cpp"; + auto Results = completions(Code, {}, Opts); EXPECT_EQ(Results.Completions.size(), 3u); TextEdit ReplacementEdit; - ReplacementEdit.range = TestCode.range(); + ReplacementEdit.range = Annotations(Code).range(); ReplacementEdit.newText = "."; for (const auto &C : Results.Completions) { EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction"); @@ -1779,13 +1744,9 @@ TEST(CompletionTest, FixItForArrowToDot) { } TEST(CompletionTest, FixItForDotToArrow) { - MockFSProvider FS; - MockCompilationDatabase CDB; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); - CodeCompleteOptions Opts; Opts.IncludeFixIts = true; - Annotations TestCode( + const char* Code = R"cpp( class Auxilary { public: @@ -1801,13 +1762,12 @@ TEST(CompletionTest, FixItForDotToArrow) { ClassWithPtr x; x[[.]]^; } - )cpp"); - auto Results = - completions(Server, TestCode.code(), TestCode.point(), {}, Opts); + )cpp"; + auto Results = completions(Code, {}, Opts); EXPECT_EQ(Results.Completions.size(), 3u); TextEdit ReplacementEdit; - ReplacementEdit.range = TestCode.range(); + ReplacementEdit.range = Annotations(Code).range(); ReplacementEdit.newText = "->"; for (const auto &C : Results.Completions) { EXPECT_TRUE(C.FixIts.empty() || C.Name == "AuxFunction"); @@ -1860,7 +1820,8 @@ TEST(CompletionTest, RenderWithFixItNonMerged) { TEST(CompletionTest, CompletionTokenRange) { MockFSProvider FS; MockCompilationDatabase CDB; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); + TestTU TU; + TU.AdditionalFiles["foo/abc/foo.h"] = ""; constexpr const char *TestCodes[] = { R"cpp( @@ -1882,13 +1843,20 @@ TEST(CompletionTest, CompletionTokenRange) { Auxilary x; x.[[]]^; } - )cpp"}; + )cpp", + R"cpp( + #include "foo/[[a^/]]foo.h" + )cpp", + R"cpp( + #include "foo/abc/[[fo^o.h"]] + )cpp", + }; for (const auto &Text : TestCodes) { Annotations TestCode(Text); - auto Results = completions(Server, TestCode.code(), TestCode.point()); - + TU.Code = TestCode.code().str(); + auto Results = completions(TU, TestCode.point()); if (Results.Completions.size() != 1) { - ADD_FAILURE() << "Results.Completions.size() != 1"; + ADD_FAILURE() << "Results.Completions.size() != 1" << Text; continue; } EXPECT_THAT(Results.Completions.front().CompletionTokenRange, @@ -2241,13 +2209,12 @@ TEST(CompletionTest, InsertTheMostPopularHeader) { } TEST(CompletionTest, NoInsertIncludeIfOnePresent) { - MockFSProvider FS; - MockCompilationDatabase CDB; - - std::string FooHeader = testPath("foo.h"); - FS.Files[FooHeader] = ""; - - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); + Annotations Test(R"cpp( + #include "foo.h" + Fun^ + )cpp"); + auto TU = TestTU::withCode(Test.code()); + TU.AdditionalFiles["foo.h"] = ""; std::string DeclFile = URI::create(testPath("foo")).toString(); Symbol Sym = func("Func"); @@ -2256,7 +2223,7 @@ TEST(CompletionTest, NoInsertIncludeIfOnePresent) { Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000); EXPECT_THAT( - completions(Server, "#include \"foo.h\"\nFun^", {Sym}).Completions, + completions(TU, Test.point(), {Sym}).Completions, UnorderedElementsAre( AllOf(Named("Func"), HasInclude("\"foo.h\""), Not(InsertInclude())))); } @@ -2273,20 +2240,15 @@ TEST(CompletionTest, MergeMacrosFromIndexAndSema) { } TEST(CompletionTest, MacroFromPreamble) { - MockFSProvider FS; - MockCompilationDatabase CDB; - std::string FooHeader = testPath("foo.h"); - FS.Files[FooHeader] = "#define CLANGD_PREAMBLE_HEADER x\n"; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); - auto Results = completions( - R"cpp(#include "foo.h" - #define CLANGD_PREAMBLE_MAIN x + Annotations Test(R"cpp(#define CLANGD_PREAMBLE_MAIN x int x = 0; #define CLANGD_MAIN x void f() { CLANGD_^ } - )cpp", - {func("CLANGD_INDEX")}); + )cpp"); + auto TU = TestTU::withCode(Test.code()); + TU.HeaderCode = "#define CLANGD_PREAMBLE_HEADER x"; + auto Results = completions(TU, Test.point(), {func("CLANGD_INDEX")}); // We should get results from the main file, including the preamble section. // However no results from included files (the index should cover them). EXPECT_THAT(Results.Completions, @@ -2399,29 +2361,22 @@ TEST(SignatureHelpTest, ConstructorInitializeFields) { } TEST(CompletionTest, IncludedCompletionKinds) { - MockFSProvider FS; - MockCompilationDatabase CDB; - std::string Subdir = testPath("sub"); - std::string SearchDirArg = (Twine("-I") + Subdir).str(); - CDB.ExtraClangFlags = {SearchDirArg.c_str()}; - std::string BarHeader = testPath("sub/bar.h"); - FS.Files[BarHeader] = ""; - ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); - auto Results = completions(Server, - R"cpp( - #include "^" - )cpp"); + Annotations Test(R"cpp(#include "^")cpp"); + auto TU = TestTU::withCode(Test.code()); + TU.AdditionalFiles["sub/bar.h"] = ""; + TU.ExtraArgs.push_back("-I" + testPath("sub")); + + auto Results = completions(TU, Test.point()); EXPECT_THAT(Results.Completions, AllOf(Has("sub/", CompletionItemKind::Folder), Has("bar.h\"", CompletionItemKind::File))); } TEST(CompletionTest, NoCrashAtNonAlphaIncludeHeader) { - auto Results = completions( + completions( R"cpp( #include "./^" )cpp"); - EXPECT_TRUE(Results.Completions.empty()); } TEST(CompletionTest, NoAllScopesCompletionWhenQualified) { @@ -2708,6 +2663,20 @@ TEST(CompletionTest, NoCrashWithIncompleteLambda) { EXPECT_THAT(Signatures, Contains(Sig("x() -> auto"))); } +TEST(CompletionTest, DelayedTemplateParsing) { + Annotations Test(R"cpp( + int xxx; + template int foo() { return xx^; } + )cpp"); + auto TU = TestTU::withCode(Test.code()); + // Even though delayed-template-parsing is on, we will disable it to provide + // completion in templates. + TU.ExtraArgs.push_back("-fdelayed-template-parsing"); + + EXPECT_THAT(completions(TU, Test.point()).Completions, + Contains(Named("xxx"))); +} + TEST(CompletionTest, CompletionRange) { const char *WithRange = "auto x = [[abc]]^"; auto Completions = completions(WithRange); diff --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp index 9334d9d17608d..00dd1f864813d 100644 --- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp +++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp @@ -61,9 +61,7 @@ MATCHER_P3(Fix, Range, Replacement, Message, arg.Edits[0].range == Range && arg.Edits[0].newText == Replacement; } -MATCHER_P(FixMessage, Message, "") { - return arg.Message == Message; -} +MATCHER_P(FixMessage, Message, "") { return arg.Message == Message; } MATCHER_P(EqualToLSPDiag, LSPDiag, "LSP diagnostic " + llvm::to_string(LSPDiag)) { @@ -258,13 +256,13 @@ TEST(DiagnosticsTest, ClangTidy) { Diag(Test.range("macroarg"), "multiple unsequenced modifications to 'y'"), AllOf( - Diag(Test.range("main"), - "use a trailing return type for this function"), - DiagSource(Diag::ClangTidy), - DiagName("modernize-use-trailing-return-type"), - // Verify that we don't have "[check-name]" suffix in the message. - WithFix(FixMessage("use a trailing return type for this function"))) - )); + Diag(Test.range("main"), + "use a trailing return type for this function"), + DiagSource(Diag::ClangTidy), + DiagName("modernize-use-trailing-return-type"), + // Verify that we don't have "[check-name]" suffix in the message. + WithFix(FixMessage( + "use a trailing return type for this function"))))); } TEST(DiagnosticTest, ClangTidySuppressionComment) { @@ -274,7 +272,11 @@ TEST(DiagnosticTest, ClangTidySuppressionComment) { double d = 8 / i; // NOLINT // NOLINTNEXTLINE double e = 8 / i; - double f = [[8]] / i; + #define BAD 8 / i + double f = BAD; // NOLINT + double g = [[8]] / i; + #define BAD2 BAD + double h = BAD2; // NOLINT } )cpp"); TestTU TU = TestTU::withCode(Main.code()); @@ -678,7 +680,7 @@ void foo() { TEST(IncludeFixerTest, NoCrashMemebrAccess) { Annotations Test(R"cpp(// error-ok struct X { int xyz; }; - void g() { X x; x.$[[xy]] } + void g() { X x; x.$[[xy]]; } )cpp"); auto TU = TestTU::withCode(Test.code()); auto Index = buildIndexWithSymbol( @@ -836,8 +838,9 @@ TEST(IncludeFixerTest, NoCrashOnTemplateInstantiations) { auto Index = buildIndexWithSymbol({}); TU.ExternalIndex = Index.get(); - EXPECT_THAT(TU.build().getDiagnostics(), - ElementsAre(Diag(Test.range(), "use of undeclared identifier 'a'"))); + EXPECT_THAT( + TU.build().getDiagnostics(), + ElementsAre(Diag(Test.range(), "use of undeclared identifier 'a'"))); } TEST(DiagsInHeaders, DiagInsideHeader) { diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index c38ccc3f9441d..7b6fff292e661 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -65,7 +65,7 @@ class TargetDeclTest : public ::testing::Test { protected: using Rel = DeclRelation; std::string Code; - std::vector Flags; + std::vector Flags; // Asserts that `Code` has a marked selection of a node `NodeType`, // and returns allTargetDecls() as PrintedDecl structs. @@ -132,6 +132,16 @@ TEST_F(TargetDeclTest, Exprs) { EXPECT_DECLS("CXXOperatorCallExpr", "void operator()(int n)"); } +TEST_F(TargetDeclTest, Recovery) { + Code = R"cpp( + // error-ok: testing behavior on broken code + int f(); + int f(int, int); + int x = [[f]](42); + )cpp"; + EXPECT_DECLS("UnresolvedLookupExpr", "int f()", "int f(int, int)"); +} + TEST_F(TargetDeclTest, UsingDecl) { Code = R"cpp( namespace foo { @@ -685,6 +695,15 @@ TEST_F(FindExplicitReferencesTest, All) { )cpp", "0: targets = {x}\n" "1: targets = {X::a}\n"}, + {R"cpp( + // error-ok: testing with broken code + int bar(); + int foo() { + return $0^bar() + $1^bar(42); + } + )cpp", + "0: targets = {bar}\n" + "1: targets = {bar}\n"}, // Namespaces and aliases. {R"cpp( namespace ns {} diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 593fb16e21948..99fd1c5724476 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1567,7 +1567,7 @@ TEST(Hover, All) { HI.Kind = index::SymbolKind::Variable; HI.NamespaceScope = ""; HI.Name = "foo"; - HI.Type = "cls > >"; + HI.Type = "cls>>"; HI.Value = "{}"; }}, { @@ -1579,7 +1579,7 @@ TEST(Hover, All) { HI.Definition = "template <> struct cls>> {}"; HI.Kind = index::SymbolKind::Struct; HI.NamespaceScope = ""; - HI.Name = "cls > >"; + HI.Name = "cls>>"; HI.Documentation = "type of nested templates."; }}, { diff --git a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp index 6a7f700e1f491..1cca429a4ea6e 100644 --- a/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp @@ -14,8 +14,10 @@ #include "TestFS.h" #include "TestTU.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ScopedPrinter.h" #include "gmock/gmock.h" #include @@ -23,6 +25,9 @@ namespace clang { namespace clangd { namespace { +using testing::IsEmpty; +using testing::SizeIs; + MATCHER_P(LineNumber, L, "") { return arg.Line == L; } MATCHER(EmptyHighlightings, "") { return arg.Tokens.empty(); } @@ -720,6 +725,77 @@ TEST(SemanticHighlighting, GeneratesHighlightsWhenFileChange) { ASSERT_EQ(Counter.Count, 1); } +// Ranges are highlighted as variables, unless highlighted as $Function etc. +std::vector tokens(llvm::StringRef MarkedText) { + Annotations A(MarkedText); + std::vector Results; + for (const Range& R : A.ranges()) + Results.push_back({HighlightingKind::Variable, R}); + for (unsigned I = 0; I < static_cast(HighlightingKind::LastKind); ++I) { + HighlightingKind Kind = static_cast(I); + for (const Range& R : A.ranges(llvm::to_string(Kind))) + Results.push_back({Kind, R}); + } + llvm::sort(Results); + return Results; +} + +TEST(SemanticHighlighting, toSemanticTokens) { + auto Results = toSemanticTokens(tokens(R"( + [[blah]] + + $Function[[big]] [[bang]] + )")); + + ASSERT_THAT(Results, SizeIs(3)); + EXPECT_EQ(Results[0].tokenType, unsigned(HighlightingKind::Variable)); + EXPECT_EQ(Results[0].deltaLine, 1u); + EXPECT_EQ(Results[0].deltaStart, 1u); + EXPECT_EQ(Results[0].length, 4u); + + EXPECT_EQ(Results[1].tokenType, unsigned(HighlightingKind::Function)); + EXPECT_EQ(Results[1].deltaLine, 2u); + EXPECT_EQ(Results[1].deltaStart, 4u); + EXPECT_EQ(Results[1].length, 3u); + + EXPECT_EQ(Results[2].tokenType, unsigned(HighlightingKind::Variable)); + EXPECT_EQ(Results[2].deltaLine, 0u); + EXPECT_EQ(Results[2].deltaStart, 4u); + EXPECT_EQ(Results[2].length, 4u); +} + +TEST(SemanticHighlighting, diffSemanticTokens) { + auto Before = toSemanticTokens(tokens(R"( + [[foo]] [[bar]] [[baz]] + [[one]] [[two]] [[three]] + )")); + EXPECT_THAT(diffTokens(Before, Before), IsEmpty()); + + auto After = toSemanticTokens(tokens(R"( + [[foo]] [[hello]] [[world]] [[baz]] + [[one]] [[two]] [[three]] + )")); + + // Replace [bar, baz] with [hello, world, baz] + auto Diff = diffTokens(Before, After); + ASSERT_THAT(Diff, SizeIs(1)); + EXPECT_EQ(1u, Diff.front().startToken); + EXPECT_EQ(2u, Diff.front().deleteTokens); + ASSERT_THAT(Diff.front().tokens, SizeIs(3)); + // hello + EXPECT_EQ(0u, Diff.front().tokens[0].deltaLine); + EXPECT_EQ(4u, Diff.front().tokens[0].deltaStart); + EXPECT_EQ(5u, Diff.front().tokens[0].length); + // world + EXPECT_EQ(0u, Diff.front().tokens[1].deltaLine); + EXPECT_EQ(6u, Diff.front().tokens[1].deltaStart); + EXPECT_EQ(5u, Diff.front().tokens[1].length); + // baz + EXPECT_EQ(0u, Diff.front().tokens[2].deltaLine); + EXPECT_EQ(6u, Diff.front().tokens[2].deltaStart); + EXPECT_EQ(3u, Diff.front().tokens[2].length); +} + TEST(SemanticHighlighting, toTheiaSemanticHighlightingInformation) { auto CreatePosition = [](int Line, int Character) -> Position { Position Pos; diff --git a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp index 3356a095515f6..0b0b7550cc525 100644 --- a/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SemanticSelectionTests.cpp @@ -24,8 +24,17 @@ namespace clang { namespace clangd { namespace { +using ::testing::ElementsAre; using ::testing::ElementsAreArray; +// front() is SR.range, back() is outermost range. +std::vector gatherRanges(const SelectionRange &SR) { + std::vector Ranges; + for (const SelectionRange *S = &SR; S; S = S->parent.get()) + Ranges.push_back(S->range); + return Ranges; +} + TEST(SemanticSelection, All) { const char *Tests[] = { R"cpp( // Single statement in a function body. @@ -78,7 +87,7 @@ TEST(SemanticSelection, All) { }]]]] )cpp", // Empty file. - "^", + "[[^]]", // FIXME: We should get the whole DeclStmt as a range. R"cpp( // Single statement in TU. [[int v = [[1^00]]]]; @@ -89,7 +98,7 @@ TEST(SemanticSelection, All) { // FIXME: No node found associated to the position. R"cpp( // Cursor in between spaces. void func() { - int v = 100 + ^ 100; + int v = 100 + [[^]] 100; } )cpp", // Structs. @@ -133,13 +142,13 @@ TEST(SemanticSelection, All) { for (const char *Test : Tests) { auto T = Annotations(Test); auto AST = TestTU::withCode(T.code()).build(); - EXPECT_THAT(llvm::cantFail(getSemanticRanges(AST, T.point())), + EXPECT_THAT(gatherRanges(llvm::cantFail(getSemanticRanges(AST, T.point()))), ElementsAreArray(T.ranges())) << Test; } } -TEST(SemanticSelection, RunViaClangDServer) { +TEST(SemanticSelection, RunViaClangdServer) { MockFSProvider FS; MockCompilationDatabase CDB; ClangdServer Server(CDB, FS, ClangdServer::optsForTest()); @@ -157,15 +166,20 @@ TEST(SemanticSelection, RunViaClangDServer) { // inp = HASH(foo(inp)); [[inp = [[HASH([[foo([[in^p]])]])]]]]; }]]]] + $empty[[^]] )cpp"; Annotations SourceAnnotations(SourceContents); FS.Files[FooCpp] = std::string(SourceAnnotations.code()); Server.addDocument(FooCpp, SourceAnnotations.code()); - auto Ranges = runSemanticRanges(Server, FooCpp, SourceAnnotations.point()); + auto Ranges = runSemanticRanges(Server, FooCpp, SourceAnnotations.points()); ASSERT_TRUE(bool(Ranges)) << "getSemanticRange returned an error: " << Ranges.takeError(); - EXPECT_THAT(*Ranges, ElementsAreArray(SourceAnnotations.ranges())); + ASSERT_EQ(Ranges->size(), SourceAnnotations.points().size()); + EXPECT_THAT(gatherRanges(Ranges->front()), + ElementsAreArray(SourceAnnotations.ranges())); + EXPECT_THAT(gatherRanges(Ranges->back()), + ElementsAre(SourceAnnotations.range("empty"))); } } // namespace } // namespace clangd diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.cpp b/clang-tools-extra/clangd/unittests/SyncAPI.cpp index 522aaed117e87..e976b5ab93894 100644 --- a/clang-tools-extra/clangd/unittests/SyncAPI.cpp +++ b/clang-tools-extra/clangd/unittests/SyncAPI.cpp @@ -146,9 +146,10 @@ RefSlab getRefs(const SymbolIndex &Index, SymbolID ID) { return std::move(Slab).build(); } -llvm::Expected> -runSemanticRanges(ClangdServer &Server, PathRef File, Position Pos) { - llvm::Optional>> Result; +llvm::Expected> +runSemanticRanges(ClangdServer &Server, PathRef File, + const std::vector &Pos) { + llvm::Optional>> Result; Server.semanticRanges(File, Pos, capture(Result)); return std::move(*Result); } diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.h b/clang-tools-extra/clangd/unittests/SyncAPI.h index 241b98d348948..22b03c6f1fa5e 100644 --- a/clang-tools-extra/clangd/unittests/SyncAPI.h +++ b/clang-tools-extra/clangd/unittests/SyncAPI.h @@ -56,8 +56,9 @@ SymbolSlab runFuzzyFind(const SymbolIndex &Index, StringRef Query); SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req); RefSlab getRefs(const SymbolIndex &Index, SymbolID ID); -llvm::Expected> -runSemanticRanges(ClangdServer &Server, PathRef File, Position Pos); +llvm::Expected> +runSemanticRanges(ClangdServer &Server, PathRef File, + const std::vector &Pos); llvm::Expected> runSwitchHeaderSource(ClangdServer &Server, PathRef File); diff --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp index 909c125aed2e0..2adcfc338cc2e 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.cpp +++ b/clang-tools-extra/clangd/unittests/TestTU.cpp @@ -20,7 +20,7 @@ namespace clang { namespace clangd { -ParsedAST TestTU::build() const { +ParseInputs TestTU::inputs() const { std::string FullFilename = testPath(Filename), FullHeaderName = testPath(HeaderFilename), ImportThunk = testPath("import_thunk.h"); @@ -34,43 +34,48 @@ ParsedAST TestTU::build() const { Files[FullHeaderName] = HeaderCode; Files[ImportThunk] = ThunkContents; - std::vector Cmd = {"clang"}; + ParseInputs Inputs; + auto& Argv = Inputs.CompileCommand.CommandLine; + Argv = {"clang"}; // FIXME: this shouldn't need to be conditional, but it breaks a // GoToDefinition test for some reason (getMacroArgExpandedLocation fails). if (!HeaderCode.empty()) { - Cmd.push_back("-include"); - Cmd.push_back(ImplicitHeaderGuard ? ImportThunk.c_str() - : FullHeaderName.c_str()); + Argv.push_back("-include"); + Argv.push_back(ImplicitHeaderGuard ? ImportThunk : FullHeaderName); // ms-compatibility changes the meaning of #import. // The default is OS-dependent (on on windows), ensure it's off. if (ImplicitHeaderGuard) - Cmd.push_back("-fno-ms-compatibility"); + Inputs.CompileCommand.CommandLine.push_back("-fno-ms-compatibility"); } - Cmd.insert(Cmd.end(), ExtraArgs.begin(), ExtraArgs.end()); + Argv.insert(Argv.end(), ExtraArgs.begin(), ExtraArgs.end()); // Put the file name at the end -- this allows the extra arg (-xc++) to // override the language setting. - Cmd.push_back(FullFilename.c_str()); - ParseInputs Inputs; + Argv.push_back(FullFilename); Inputs.CompileCommand.Filename = FullFilename; - Inputs.CompileCommand.CommandLine = {Cmd.begin(), Cmd.end()}; Inputs.CompileCommand.Directory = testRoot(); Inputs.Contents = Code; Inputs.FS = buildTestFS(Files); Inputs.Opts = ParseOptions(); + Inputs.Opts.BuildRecoveryAST = true; Inputs.Opts.ClangTidyOpts.Checks = ClangTidyChecks; Inputs.Opts.ClangTidyOpts.WarningsAsErrors = ClangTidyWarningsAsErrors; Inputs.Index = ExternalIndex; if (Inputs.Index) Inputs.Opts.SuggestMissingIncludes = true; + return Inputs; +} + +ParsedAST TestTU::build() const { + auto Inputs = inputs(); StoreDiags Diags; auto CI = buildCompilerInvocation(Inputs, Diags); assert(CI && "Failed to build compilation invocation."); auto Preamble = - buildPreamble(FullFilename, *CI, + buildPreamble(testPath(Filename), *CI, /*OldPreamble=*/nullptr, Inputs, /*StoreInMemory=*/true, /*PreambleCallback=*/nullptr); - auto AST = - buildAST(FullFilename, std::move(CI), Diags.take(), Inputs, Preamble); + auto AST = buildAST(testPath(Filename), std::move(CI), Diags.take(), Inputs, + Preamble); if (!AST.hasValue()) { ADD_FAILURE() << "Failed to build code:\n" << Code; llvm_unreachable("Failed to build TestTU!"); @@ -79,9 +84,17 @@ ParsedAST TestTU::build() const { // This guards against accidental syntax errors silently subverting tests. // error-ok is awfully primitive - using clang -verify would be nicer. // Ownership and layering makes it pretty hard. - if (llvm::none_of(Files, [](const auto &KV) { - return llvm::StringRef(KV.second).contains("error-ok"); - })) { + bool ErrorOk = [&, this] { + llvm::StringLiteral Marker = "error-ok"; + if (llvm::StringRef(Code).contains(Marker) || + llvm::StringRef(HeaderCode).contains(Marker)) + return true; + for (const auto& KV : this->AdditionalFiles) + if (llvm::StringRef(KV.second).contains(Marker)) + return true; + return false; + }(); + if (!ErrorOk) { for (const auto &D : AST->getDiagnostics()) if (D.Severity >= DiagnosticsEngine::Error) { ADD_FAILURE() diff --git a/clang-tools-extra/clangd/unittests/TestTU.h b/clang-tools-extra/clangd/unittests/TestTU.h index 4668543d5b4db..229f65a4b95c7 100644 --- a/clang-tools-extra/clangd/unittests/TestTU.h +++ b/clang-tools-extra/clangd/unittests/TestTU.h @@ -17,6 +17,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTTU_H #define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTTU_H +#include "Compiler.h" #include "ParsedAST.h" #include "Path.h" #include "index/Index.h" @@ -54,7 +55,7 @@ struct TestTU { llvm::StringMap AdditionalFiles; // Extra arguments for the compiler invocation. - std::vector ExtraArgs; + std::vector ExtraArgs; llvm::Optional ClangTidyChecks; llvm::Optional ClangTidyWarningsAsErrors; @@ -67,6 +68,7 @@ struct TestTU { // By default, build() will report Error diagnostics as GTest errors. // Suppress this behavior by adding an 'error-ok' comment to the code. ParsedAST build() const; + ParseInputs inputs() const; SymbolSlab headerSymbols() const; std::unique_ptr index() const; }; diff --git a/clang-tools-extra/clangd/unittests/TweakTesting.h b/clang-tools-extra/clangd/unittests/TweakTesting.h index 10186f859bae2..c771149a72fc5 100644 --- a/clang-tools-extra/clangd/unittests/TweakTesting.h +++ b/clang-tools-extra/clangd/unittests/TweakTesting.h @@ -66,7 +66,7 @@ class TweakTest : public ::testing::Test { llvm::StringRef FileName = "TestTU.cpp"; // Extra flags passed to the compilation in apply(). - std::vector ExtraArgs; + std::vector ExtraArgs; // Context in which snippets of code should be placed to run tweaks. CodeContext Context = File; diff --git a/clang-tools-extra/clangd/unittests/TweakTests.cpp b/clang-tools-extra/clangd/unittests/TweakTests.cpp index cae922ffcb955..b5d6117217b63 100644 --- a/clang-tools-extra/clangd/unittests/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp @@ -2390,6 +2390,250 @@ TEST_F(DefineOutlineTest, FailsMacroSpecifier) { EXPECT_EQ(apply(Case.first), Case.second); } } + +TWEAK_TEST(AddUsing); +TEST_F(AddUsingTest, Prepare) { + const std::string Header = R"cpp( +#define NS(name) one::two::name +namespace one { +void oo() {} +namespace two { +enum ee {}; +void ff() {} +class cc { +public: + struct st {}; + static void mm() {} +}; +} +})cpp"; + + EXPECT_AVAILABLE(Header + "void fun() { o^n^e^:^:^t^w^o^:^:^f^f(); }"); + EXPECT_AVAILABLE(Header + "void fun() { o^n^e^::^o^o(); }"); + EXPECT_AVAILABLE(Header + "void fun() { o^n^e^:^:^t^w^o^:^:^e^e E; }"); + EXPECT_AVAILABLE(Header + "void fun() { o^n^e^:^:^t^w^o:^:^c^c C; }"); + EXPECT_UNAVAILABLE(Header + + "void fun() { o^n^e^:^:^t^w^o^:^:^c^c^:^:^m^m(); }"); + EXPECT_UNAVAILABLE(Header + + "void fun() { o^n^e^:^:^t^w^o^:^:^c^c^:^:^s^t inst; }"); + EXPECT_UNAVAILABLE(Header + + "void fun() { o^n^e^:^:^t^w^o^:^:^c^c^:^:^s^t inst; }"); + EXPECT_UNAVAILABLE(Header + "void fun() { N^S(c^c) inst; }"); +} + +TEST_F(AddUsingTest, Apply) { + FileName = "test.cpp"; + struct { + llvm::StringRef TestSource; + llvm::StringRef ExpectedSource; + } Cases[]{{ + // Function, no other using, namespace. + R"cpp( +#include "test.hpp" +namespace { +void fun() { + ^o^n^e^:^:^t^w^o^:^:^f^f(); +} +})cpp", + R"cpp( +#include "test.hpp" +namespace {using one::two::ff; + +void fun() { + ff(); +} +})cpp", + }, + // Type, no other using, namespace. + { + R"cpp( +#include "test.hpp" +namespace { +void fun() { + ::on^e::t^wo::c^c inst; +} +})cpp", + R"cpp( +#include "test.hpp" +namespace {using ::one::two::cc; + +void fun() { + cc inst; +} +})cpp", + }, + // Type, no other using, no namespace. + { + R"cpp( +#include "test.hpp" + +void fun() { + on^e::t^wo::e^e inst; +})cpp", + R"cpp( +#include "test.hpp" + +using one::two::ee; + +void fun() { + ee inst; +})cpp"}, + // Function, other usings. + { + R"cpp( +#include "test.hpp" + +using one::two::cc; +using one::two::ee; + +namespace { +void fun() { + one::two::f^f(); +} +})cpp", + R"cpp( +#include "test.hpp" + +using one::two::cc; +using one::two::ff;using one::two::ee; + +namespace { +void fun() { + ff(); +} +})cpp", + }, + // Function, other usings inside namespace. + { + R"cpp( +#include "test.hpp" + +using one::two::cc; + +namespace { + +using one::two::ff; + +void fun() { + o^ne::o^o(); +} +})cpp", + R"cpp( +#include "test.hpp" + +using one::two::cc; + +namespace { + +using one::oo;using one::two::ff; + +void fun() { + oo(); +} +})cpp"}, + // Using comes after cursor. + { + R"cpp( +#include "test.hpp" + +namespace { + +void fun() { + one::t^wo::ff(); +} + +using one::two::cc; + +})cpp", + R"cpp( +#include "test.hpp" + +namespace {using one::two::ff; + + +void fun() { + ff(); +} + +using one::two::cc; + +})cpp"}, + // Pointer type. + {R"cpp( +#include "test.hpp" + +void fun() { + one::two::c^c *p; +})cpp", + R"cpp( +#include "test.hpp" + +using one::two::cc; + +void fun() { + cc *p; +})cpp"}, + // Namespace declared via macro. + {R"cpp( +#include "test.hpp" +#define NS_BEGIN(name) namespace name { + +NS_BEGIN(foo) + +void fun() { + one::two::f^f(); +} +})cpp", + R"cpp( +#include "test.hpp" +#define NS_BEGIN(name) namespace name { + +using one::two::ff; + +NS_BEGIN(foo) + +void fun() { + ff(); +} +})cpp"}, + // Inside macro argument. + {R"cpp( +#include "test.hpp" +#define CALL(name) name() + +void fun() { + CALL(one::t^wo::ff); +})cpp", + R"cpp( +#include "test.hpp" +#define CALL(name) name() + +using one::two::ff; + +void fun() { + CALL(ff); +})cpp"}}; + llvm::StringMap EditedFiles; + for (const auto &Case : Cases) { + for (const auto &SubCase : expandCases(Case.TestSource)) { + ExtraFiles["test.hpp"] = R"cpp( +namespace one { +void oo() {} +namespace two { +enum ee {}; +void ff() {} +class cc { +public: + struct st { struct nested {}; }; + static void mm() {} +}; +} +})cpp"; + EXPECT_EQ(apply(SubCase, &EditedFiles), Case.ExpectedSource); + } + } +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index fc36dfa42d7f2..ce7f76ccf4f44 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -358,15 +358,15 @@ TEST(LocateSymbol, All) { )cpp", R"cpp(// Forward class declaration - class Foo; - class [[Foo]] {}; + class $decl[[Foo]]; + class $def[[Foo]] {}; F^oo* foo(); )cpp", R"cpp(// Function declaration - void foo(); + void $decl[[foo]](); void g() { f^oo(); } - void [[foo]]() {} + void $def[[foo]]() {} )cpp", R"cpp( @@ -1121,6 +1121,30 @@ TEST(FindReferences, WithinAST) { } } +TEST(FindReferences, MainFileReferencesOnly) { + llvm::StringRef Test = + R"cpp( + void test() { + int [[fo^o]] = 1; + // refs not from main file should not be included. + #include "foo.inc" + })cpp"; + + Annotations Code(Test); + auto TU = TestTU::withCode(Code.code()); + TU.AdditionalFiles["foo.inc"] = R"cpp( + foo = 3; + )cpp"; + auto AST = TU.build(); + + std::vector> ExpectedLocations; + for (const auto &R : Code.ranges()) + ExpectedLocations.push_back(RangeIs(R)); + EXPECT_THAT(findReferences(AST, Code.point(), 0).References, + ElementsAreArray(ExpectedLocations)) + << Test; +} + TEST(FindReferences, ExplicitSymbols) { const char *Tests[] = { R"cpp( diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability-convert-member-functions-to-static.rst b/clang-tools-extra/docs/clang-tidy/checks/readability-convert-member-functions-to-static.rst index 891f6be637142..c2f05cf589eac 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability-convert-member-functions-to-static.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability-convert-member-functions-to-static.rst @@ -10,5 +10,5 @@ After applying modifications as suggested by the check, runnnig the check again might find more opportunities to mark member functions ``static``. After making a member function ``static``, you might want to run the check -`readability-static-accessed-through-instance` to replace calls like +`readability-static-accessed-through-instance `_ to replace calls like ``Instance.method()`` by ``Class::method()``. diff --git a/clang-tools-extra/modularize/CoverageChecker.cpp b/clang-tools-extra/modularize/CoverageChecker.cpp index 9df53d26c2e97..4246df9483d09 100644 --- a/clang-tools-extra/modularize/CoverageChecker.cpp +++ b/clang-tools-extra/modularize/CoverageChecker.cpp @@ -338,7 +338,7 @@ bool CoverageChecker::collectFileSystemHeaders() { } // Sort it, because different file systems might order the file differently. - std::sort(FileSystemHeaders.begin(), FileSystemHeaders.end()); + llvm::sort(FileSystemHeaders); return true; } diff --git a/clang-tools-extra/modularize/Modularize.cpp b/clang-tools-extra/modularize/Modularize.cpp index 5076bd9ee601e..b1efb0e7996a1 100644 --- a/clang-tools-extra/modularize/Modularize.cpp +++ b/clang-tools-extra/modularize/Modularize.cpp @@ -509,7 +509,7 @@ class EntityMap : public StringMap > { HEnd = CurHeaderContents.end(); H != HEnd; ++H) { // Sort contents. - std::sort(H->second.begin(), H->second.end()); + llvm::sort(H->second); // Check whether we've seen this header before. DenseMap::iterator KnownH = diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-use-default-member-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-default-member-init.cpp index 3570fcff4a5cc..60344e06dc31d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize-use-default-member-init.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-default-member-init.cpp @@ -432,3 +432,17 @@ class FunctionTryBlock { // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: use default member initializer for 'k' [modernize-use-default-member-init] // CHECK-FIXES: int i{5}, k{8}; }; + +struct PR45363 { + // Ensure no warning is emitted here + PR45363(int i = 0) : m_i{i} {} + int m_i; +}; + +struct EmptyBracedIntDefault { + EmptyBracedIntDefault() : m_i{} {} + int m_i; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'm_i' [modernize-use-default-member-init] + // CHECK-FIXES: {{^ }}EmptyBracedIntDefault() {} + // CHECK-FIXES-NEXT: {{^ }}int m_i{}; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp index eb3316a4a04e9..2eccc9066fa6b 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp @@ -247,19 +247,19 @@ typedef Q Q3_t; typedef TwoArgTemplate >, S<(0 < 0), Q > > Nested_t; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Nested_t = TwoArgTemplate >, S<(0 < 0), Q > >; +// CHECK-FIXES: using Nested_t = TwoArgTemplate>, S<(0 < 0), Q>>; template class Variadic {}; typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > > +// CHECK-FIXES: using Variadic_t = Variadic>, S<(0 < 0), Variadic>>> typedef Variadic >, S<(0 < 0), Variadic > > > Variadic_t, *Variadic_p; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' // CHECK-MESSAGES: :[[@LINE-2]]:103: warning: use 'using' instead of 'typedef' -// CHECK-FIXES: using Variadic_t = Variadic >, S<(0 < 0), Variadic > > >; +// CHECK-FIXES: using Variadic_t = Variadic>, S<(0 < 0), Variadic>>>; // CHECK-FIXES-NEXT: using Variadic_p = Variadic_t*; typedef struct { int a; } R_t, *R_p; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-cstr.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-cstr.cpp index 1773dc57a8d88..2561b81805bda 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-cstr.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability-redundant-string-cstr.cpp @@ -220,3 +220,27 @@ void m1(std::string&&) { m1tp m1p2 = m1; m1p2(s.c_str()); } + +namespace PR45286 { +struct Foo { + void func(const std::string &) {} + void func2(std::string &&) {} +}; + +void bar() { + std::string Str{"aaa"}; + Foo Foo; + Foo.func(Str.c_str()); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant call to 'c_str' [readability-redundant-string-cstr] + // CHECK-FIXES: {{^ }}Foo.func(Str);{{$}} + + // Ensure it doesn't transform Binding to r values + Foo.func2(Str.c_str()); + + // Ensure its not confused by parens + Foo.func((Str.c_str())); + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant call to 'c_str' [readability-redundant-string-cstr] + // CHECK-FIXES: {{^ }}Foo.func((Str));{{$}} + Foo.func2((Str.c_str())); +} +} // namespace PR45286 diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 9ddb633a2899d..75ab1a86a170f 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -226,7 +226,7 @@ set(C_INCLUDE_DIRS "" CACHE STRING "Colon separated list of directories clang will search for headers.") set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." ) -set(DEFAULT_SYSROOT "" CACHE PATH +set(DEFAULT_SYSROOT "" CACHE STRING "Default to all compiler invocations for --sysroot=." ) set(ENABLE_LINKER_BUILD_ID OFF CACHE BOOL "pass --build-id to ld") @@ -306,6 +306,8 @@ if (NOT DEFINED MATCHED_ARCH OR "${CMAKE_MATCH_1}" LESS 35) "Default architecture for OpenMP offloading to Nvidia GPUs." FORCE) endif() +set(CLANG_SYSTEMZ_DEFAULT_ARCH "z10" CACHE STRING "SystemZ Default Arch") + set(CLANG_VENDOR ${PACKAGE_VENDOR} CACHE STRING "Vendor-specific text for showing with version information.") diff --git a/clang/cmake/caches/CrossWinToARMLinux.cmake b/clang/cmake/caches/CrossWinToARMLinux.cmake index 0d359a1609a5e..3d1e961ada8d0 100644 --- a/clang/cmake/caches/CrossWinToARMLinux.cmake +++ b/clang/cmake/caches/CrossWinToARMLinux.cmake @@ -86,6 +86,8 @@ set(LIBCXXABI_TARGET_TRIPLE "${CMAKE_C_COMPILER_TARGET}" CACHE S set(LIBCXXABI_SYSROOT "${DEFAULT_SYSROOT}" CACHE STRING "") set(LIBCXXABI_LINK_TESTS_WITH_SHARED_LIBCXXABI OFF CACHE BOOL "") set(LIBCXXABI_LINK_TESTS_WITH_SHARED_LIBCXX OFF CACHE BOOL "") +set(LIBCXX_LINK_TESTS_WITH_SHARED_LIBCXXABI OFF CACHE BOOL "") +set(LIBCXX_LINK_TESTS_WITH_SHARED_LIBCXX OFF CACHE BOOL "") set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "") set(LIBCXX_TARGET_TRIPLE "${CMAKE_C_COMPILER_TARGET}" CACHE STRING "") diff --git a/clang/cmake/modules/AddClang.cmake b/clang/cmake/modules/AddClang.cmake index 577cc11ab015b..c1bb386de6f77 100644 --- a/clang/cmake/modules/AddClang.cmake +++ b/clang/cmake/modules/AddClang.cmake @@ -17,7 +17,7 @@ function(clang_tablegen) message(FATAL_ERROR "SOURCE source-file required by clang_tablegen") endif() - set( CLANG_TABLEGEN_ARGUMENTS -I ${CLANG_SOURCE_DIR}/include ) + set( CLANG_TABLEGEN_ARGUMENTS "" ) set( LLVM_TARGET_DEFINITIONS ${CTG_SOURCE} ) tablegen(CLANG ${CTG_UNPARSED_ARGUMENTS} ${CLANG_TABLEGEN_ARGUMENTS}) diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst index 3f0e471e852a9..511f3145e7e80 100644 --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -2625,6 +2625,10 @@ Use Intel MCU ABI Generate branches with extended addressability, usually via indirect jumps. +.. option:: -mlvi-cfi, -mno-lvi-cfi + +Enable only control-flow mitigations for Load Value Injection (LVI) + .. option:: -mmacosx-version-min=, -mmacos-version-min= Set Mac OS X deployment target @@ -3145,6 +3149,8 @@ X86 .. option:: -msahf, -mno-sahf +.. option:: -mserialize, -mno-serialize + .. option:: -msgx, -mno-sgx .. option:: -msha, -mno-sha diff --git a/clang/docs/ClangPlugins.rst b/clang/docs/ClangPlugins.rst index 7e33ea33c0df5..4194491d396ae 100644 --- a/clang/docs/ClangPlugins.rst +++ b/clang/docs/ClangPlugins.rst @@ -110,6 +110,9 @@ attribute, are: * ``existsInTarget``, which checks if the attribute is permitted for the given target. +To see a working example of an attribute plugin, see `the Attribute.cpp example +`_. + Putting it all together ======================= diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst index 209a774405372..7fef9e867885a 100644 --- a/clang/docs/OpenMPSupport.rst +++ b/clang/docs/OpenMPSupport.rst @@ -229,7 +229,7 @@ implementation. +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | base language | lambda support | :good:`done` | | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ -| misc extension | array shaping | :part:`worked on` | D74144 | +| misc extension | array shaping | :good:`done` | D74144 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | misc extension | library shutdown (omp_pause_resource[_all]) | :none:`unclaimed parts` | D55078 | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ad13fb1b3e95f..a8163cad9fde0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -111,7 +111,9 @@ New Pragmas in Clang Attribute Changes in Clang -------------------------- -- ... +- Attributes can now be specified by clang plugins. See the + `Clang Plugins `_ documentation for + details. Windows Support --------------- diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp new file mode 100644 index 0000000000000..998f175dae546 --- /dev/null +++ b/clang/examples/Attribute/Attribute.cpp @@ -0,0 +1,81 @@ +//===- Attribute.cpp ------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Example clang plugin which adds an an annotation to file-scope declarations +// with the 'example' attribute. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "llvm/IR/Attributes.h" +using namespace clang; + +namespace { + +struct ExampleAttrInfo : public ParsedAttrInfo { + ExampleAttrInfo() { + // Can take an optional string argument (the check that the argument + // actually is a string happens in handleDeclAttribute). + OptArgs = 1; + // GNU-style __attribute__(("example")) and C++-style [[example]] and + // [[plugin::example]] supported. + static constexpr Spelling S[] = {{ParsedAttr::AS_GNU, "example"}, + {ParsedAttr::AS_CXX11, "example"}, + {ParsedAttr::AS_CXX11, "plugin::example"}}; + Spellings = S; + } + + bool diagAppertainsToDecl(Sema &S, const ParsedAttr &Attr, + const Decl *D) const override { + // This attribute appertains to functions only. + if (!isa(D)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) + << Attr << "functions"; + return false; + } + return true; + } + + AttrHandling handleDeclAttribute(Sema &S, Decl *D, + const ParsedAttr &Attr) const override { + // Check if the decl is at file scope. + if (!D->getDeclContext()->isFileContext()) { + unsigned ID = S.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, + "'example' attribute only allowed at file scope"); + S.Diag(Attr.getLoc(), ID); + return AttributeNotApplied; + } + // Check if we have an optional string argument. + StringRef Str = ""; + if (Attr.getNumArgs() > 0) { + Expr *ArgExpr = Attr.getArgAsExpr(0); + StringLiteral *Literal = + dyn_cast(ArgExpr->IgnoreParenCasts()); + if (Literal) { + Str = Literal->getString(); + } else { + S.Diag(ArgExpr->getExprLoc(), diag::err_attribute_argument_type) + << Attr.getAttrName() << AANT_ArgumentString; + return AttributeNotApplied; + } + } + // Attach an annotate attribute to the Decl. + D->addAttr(AnnotateAttr::Create(S.Context, "example(" + Str.str() + ")", + Attr.getRange())); + return AttributeApplied; + } +}; + +} // namespace + +static ParsedAttrInfoRegistry::Add X("example", ""); diff --git a/clang/examples/Attribute/CMakeLists.txt b/clang/examples/Attribute/CMakeLists.txt new file mode 100644 index 0000000000000..19323bb0962bc --- /dev/null +++ b/clang/examples/Attribute/CMakeLists.txt @@ -0,0 +1,11 @@ +add_llvm_library(Attribute MODULE Attribute.cpp PLUGIN_TOOL clang) + +if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN)) + target_link_libraries(AnnotateFunctions ${cmake_2_8_12_PRIVATE} + clangAST + clangBasic + clangFrontend + clangLex + LLVMSupport + ) +endif() diff --git a/clang/examples/CMakeLists.txt b/clang/examples/CMakeLists.txt index e4fedf3682e89..c014b3ddfe97b 100644 --- a/clang/examples/CMakeLists.txt +++ b/clang/examples/CMakeLists.txt @@ -6,3 +6,4 @@ endif() add_subdirectory(clang-interpreter) add_subdirectory(PrintFunctionNames) add_subdirectory(AnnotateFunctions) +add_subdirectory(Attribute) diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index ad2bb6a76c438..0acd50021ed8d 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -35,22 +35,17 @@ #define CINDEX_VERSION_MAJOR 0 #define CINDEX_VERSION_MINOR 59 -#define CINDEX_VERSION_ENCODE(major, minor) ( \ - ((major) * 10000) \ - + ((minor) * 1)) +#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1)) -#define CINDEX_VERSION CINDEX_VERSION_ENCODE( \ - CINDEX_VERSION_MAJOR, \ - CINDEX_VERSION_MINOR ) +#define CINDEX_VERSION \ + CINDEX_VERSION_ENCODE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR) -#define CINDEX_VERSION_STRINGIZE_(major, minor) \ - #major"."#minor -#define CINDEX_VERSION_STRINGIZE(major, minor) \ - CINDEX_VERSION_STRINGIZE_(major, minor) +#define CINDEX_VERSION_STRINGIZE_(major, minor) #major "." #minor +#define CINDEX_VERSION_STRINGIZE(major, minor) \ + CINDEX_VERSION_STRINGIZE_(major, minor) -#define CINDEX_VERSION_STRING CINDEX_VERSION_STRINGIZE( \ - CINDEX_VERSION_MAJOR, \ - CINDEX_VERSION_MINOR) +#define CINDEX_VERSION_STRING \ + CINDEX_VERSION_STRINGIZE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR) LLVM_CLANG_C_EXTERN_C_BEGIN @@ -382,7 +377,7 @@ typedef struct { * \param outID stores the returned CXFileUniqueID. * \returns If there was a failure getting the unique ID, returns non-zero, * otherwise returns 0. -*/ + */ CINDEX_LINKAGE int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID); /** @@ -390,8 +385,8 @@ CINDEX_LINKAGE int clang_getFileUniqueID(CXFile file, CXFileUniqueID *outID); * multiple inclusions, either with the conventional * \#ifndef/\#define/\#endif macro guards or with \#pragma once. */ -CINDEX_LINKAGE unsigned -clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, CXFile file); +CINDEX_LINKAGE unsigned clang_isFileMultipleIncludeGuarded(CXTranslationUnit tu, + CXFile file); /** * Retrieve a file handle within the given translation unit. @@ -496,8 +491,7 @@ CINDEX_LINKAGE unsigned clang_equalLocations(CXSourceLocation loc1, * in a particular translation unit. */ CINDEX_LINKAGE CXSourceLocation clang_getLocation(CXTranslationUnit tu, - CXFile file, - unsigned line, + CXFile file, unsigned line, unsigned column); /** * Retrieves the source location associated with a given character offset @@ -566,8 +560,7 @@ CINDEX_LINKAGE int clang_Range_isNull(CXSourceRange range); * buffer to which the given source location points. */ CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location, - CXFile *file, - unsigned *line, + CXFile *file, unsigned *line, unsigned *column, unsigned *offset); @@ -613,8 +606,7 @@ CINDEX_LINKAGE void clang_getExpansionLocation(CXSourceLocation location, */ CINDEX_LINKAGE void clang_getPresumedLocation(CXSourceLocation location, CXString *filename, - unsigned *line, - unsigned *column); + unsigned *line, unsigned *column); /** * Legacy API to retrieve the file, line, column, and offset represented @@ -625,8 +617,7 @@ CINDEX_LINKAGE void clang_getPresumedLocation(CXSourceLocation location, * details. */ CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location, - CXFile *file, - unsigned *line, + CXFile *file, unsigned *line, unsigned *column, unsigned *offset); @@ -653,8 +644,7 @@ CINDEX_LINKAGE void clang_getInstantiationLocation(CXSourceLocation location, * buffer to which the given source location points. */ CINDEX_LINKAGE void clang_getSpellingLocation(CXSourceLocation location, - CXFile *file, - unsigned *line, + CXFile *file, unsigned *line, unsigned *column, unsigned *offset); @@ -682,10 +672,8 @@ CINDEX_LINKAGE void clang_getSpellingLocation(CXSourceLocation location, * buffer to which the given source location points. */ CINDEX_LINKAGE void clang_getFileLocation(CXSourceLocation location, - CXFile *file, - unsigned *line, - unsigned *column, - unsigned *offset); + CXFile *file, unsigned *line, + unsigned *column, unsigned *offset); /** * Retrieve a source location representing the first character within a @@ -727,7 +715,8 @@ CINDEX_LINKAGE CXSourceRangeList *clang_getSkippedRanges(CXTranslationUnit tu, * The preprocessor will skip lines when they are surrounded by an * if/ifdef/ifndef directive whose condition does not evaluate to true. */ -CINDEX_LINKAGE CXSourceRangeList *clang_getAllSkippedRanges(CXTranslationUnit tu); +CINDEX_LINKAGE CXSourceRangeList * +clang_getAllSkippedRanges(CXTranslationUnit tu); /** * Destroy the given \c CXSourceRangeList. @@ -758,7 +747,7 @@ enum CXDiagnosticSeverity { * This diagnostic is a note that should be attached to the * previous (non-note) diagnostic. */ - CXDiagnostic_Note = 1, + CXDiagnostic_Note = 1, /** * This diagnostic indicates suspicious code that may not be @@ -769,14 +758,14 @@ enum CXDiagnosticSeverity { /** * This diagnostic indicates that the code is ill-formed. */ - CXDiagnostic_Error = 3, + CXDiagnostic_Error = 3, /** * This diagnostic indicates that the code is ill-formed such * that future parser recovery is unlikely to produce useful * results. */ - CXDiagnostic_Fatal = 4 + CXDiagnostic_Fatal = 4 }; /** @@ -849,9 +838,8 @@ enum CXLoadDiag_Error { * \returns A loaded CXDiagnosticSet if successful, and NULL otherwise. These * diagnostics should be released using clang_disposeDiagnosticSet(). */ -CINDEX_LINKAGE CXDiagnosticSet clang_loadDiagnostics(const char *file, - enum CXLoadDiag_Error *error, - CXString *errorString); +CINDEX_LINKAGE CXDiagnosticSet clang_loadDiagnostics( + const char *file, enum CXLoadDiag_Error *error, CXString *errorString); /** * Release a CXDiagnosticSet and all of its contained diagnostics. @@ -891,7 +879,7 @@ CINDEX_LINKAGE CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, * \param Unit the translation unit to query. */ CINDEX_LINKAGE CXDiagnosticSet - clang_getDiagnosticSetFromTU(CXTranslationUnit Unit); +clang_getDiagnosticSetFromTU(CXTranslationUnit Unit); /** * Destroy a diagnostic. @@ -997,7 +985,7 @@ CINDEX_LINKAGE unsigned clang_defaultDiagnosticDisplayOptions(void); * Determine the severity of the given diagnostic. */ CINDEX_LINKAGE enum CXDiagnosticSeverity -clang_getDiagnosticSeverity(CXDiagnostic); + clang_getDiagnosticSeverity(CXDiagnostic); /** * Retrieve the source location of the given diagnostic. @@ -1049,8 +1037,8 @@ CINDEX_LINKAGE unsigned clang_getDiagnosticCategory(CXDiagnostic); * * \returns The name of the given diagnostic category. */ -CINDEX_DEPRECATED CINDEX_LINKAGE -CXString clang_getDiagnosticCategoryName(unsigned Category); +CINDEX_DEPRECATED CINDEX_LINKAGE CXString +clang_getDiagnosticCategoryName(unsigned Category); /** * Retrieve the diagnostic category text for a given diagnostic. @@ -1112,9 +1100,8 @@ CINDEX_LINKAGE unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diagnostic); * \returns A string containing text that should be replace the source * code indicated by the \c ReplacementRange. */ -CINDEX_LINKAGE CXString clang_getDiagnosticFixIt(CXDiagnostic Diagnostic, - unsigned FixIt, - CXSourceRange *ReplacementRange); +CINDEX_LINKAGE CXString clang_getDiagnosticFixIt( + CXDiagnostic Diagnostic, unsigned FixIt, CXSourceRange *ReplacementRange); /** * @} @@ -1177,12 +1164,9 @@ clang_getTranslationUnitSpelling(CXTranslationUnit CTUnit); * guarantee their validity until the call to this function returns. */ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( - CXIndex CIdx, - const char *source_filename, - int num_clang_command_line_args, - const char * const *clang_command_line_args, - unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files); + CXIndex CIdx, const char *source_filename, int num_clang_command_line_args, + const char *const *clang_command_line_args, unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files); /** * Same as \c clang_createTranslationUnit2, but returns @@ -1190,9 +1174,8 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnitFromSourceFile( * routine returns a \c NULL \c CXTranslationUnit, without further detailed * error codes. */ -CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( - CXIndex CIdx, - const char *ast_filename); +CINDEX_LINKAGE CXTranslationUnit +clang_createTranslationUnit(CXIndex CIdx, const char *ast_filename); /** * Create a translation unit from an AST file (\c -emit-ast). @@ -1202,10 +1185,9 @@ CINDEX_LINKAGE CXTranslationUnit clang_createTranslationUnit( * * \returns Zero on success, otherwise returns an error code. */ -CINDEX_LINKAGE enum CXErrorCode clang_createTranslationUnit2( - CXIndex CIdx, - const char *ast_filename, - CXTranslationUnit *out_TU); +CINDEX_LINKAGE enum CXErrorCode +clang_createTranslationUnit2(CXIndex CIdx, const char *ast_filename, + CXTranslationUnit *out_TU); /** * Flags that control the creation of translation units. @@ -1383,14 +1365,11 @@ CINDEX_LINKAGE unsigned clang_defaultEditingTranslationUnitOptions(void); * routine returns a \c NULL \c CXTranslationUnit, without further detailed * error codes. */ -CINDEX_LINKAGE CXTranslationUnit -clang_parseTranslationUnit(CXIndex CIdx, - const char *source_filename, - const char *const *command_line_args, - int num_command_line_args, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - unsigned options); +CINDEX_LINKAGE CXTranslationUnit clang_parseTranslationUnit( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options); /** * Parse the given source file and the translation unit corresponding @@ -1436,15 +1415,11 @@ clang_parseTranslationUnit(CXIndex CIdx, * * \returns Zero on success, otherwise returns an error code. */ -CINDEX_LINKAGE enum CXErrorCode -clang_parseTranslationUnit2(CXIndex CIdx, - const char *source_filename, - const char *const *command_line_args, - int num_command_line_args, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - unsigned options, - CXTranslationUnit *out_TU); +CINDEX_LINKAGE enum CXErrorCode clang_parseTranslationUnit2( + CXIndex CIdx, const char *source_filename, + const char *const *command_line_args, int num_command_line_args, + struct CXUnsavedFile *unsaved_files, unsigned num_unsaved_files, + unsigned options, CXTranslationUnit *out_TU); /** * Same as clang_parseTranslationUnit2 but requires a full command line @@ -1623,14 +1598,14 @@ CINDEX_LINKAGE unsigned clang_defaultReparseOptions(CXTranslationUnit TU); * \c clang_disposeTranslationUnit(TU). The error codes returned by this * routine are described by the \c CXErrorCode enum. */ -CINDEX_LINKAGE int clang_reparseTranslationUnit(CXTranslationUnit TU, - unsigned num_unsaved_files, - struct CXUnsavedFile *unsaved_files, - unsigned options); +CINDEX_LINKAGE int +clang_reparseTranslationUnit(CXTranslationUnit TU, unsigned num_unsaved_files, + struct CXUnsavedFile *unsaved_files, + unsigned options); /** - * Categorizes how memory is being used by a translation unit. - */ + * Categorizes how memory is being used by a translation unit. + */ enum CXTUResourceUsageKind { CXTUResourceUsage_AST = 1, CXTUResourceUsage_Identifiers = 2, @@ -1648,16 +1623,16 @@ enum CXTUResourceUsageKind { CXTUResourceUsage_Preprocessor_HeaderSearch = 14, CXTUResourceUsage_MEMORY_IN_BYTES_BEGIN = CXTUResourceUsage_AST, CXTUResourceUsage_MEMORY_IN_BYTES_END = - CXTUResourceUsage_Preprocessor_HeaderSearch, + CXTUResourceUsage_Preprocessor_HeaderSearch, CXTUResourceUsage_First = CXTUResourceUsage_AST, CXTUResourceUsage_Last = CXTUResourceUsage_Preprocessor_HeaderSearch }; /** - * Returns the human-readable null-terminated C string that represents - * the name of the memory category. This string should never be freed. - */ + * Returns the human-readable null-terminated C string that represents + * the name of the memory category. This string should never be freed. + */ CINDEX_LINKAGE const char *clang_getTUResourceUsageName(enum CXTUResourceUsageKind kind); @@ -1670,8 +1645,8 @@ typedef struct CXTUResourceUsageEntry { } CXTUResourceUsageEntry; /** - * The memory usage of a CXTranslationUnit, broken into categories. - */ + * The memory usage of a CXTranslationUnit, broken into categories. + */ typedef struct CXTUResourceUsage { /* Private data member, used for queries. */ void *data; @@ -1686,10 +1661,11 @@ typedef struct CXTUResourceUsage { } CXTUResourceUsage; /** - * Return the memory usage of a translation unit. This object - * should be released with clang_disposeCXTUResourceUsage(). - */ -CINDEX_LINKAGE CXTUResourceUsage clang_getCXTUResourceUsage(CXTranslationUnit TU); + * Return the memory usage of a translation unit. This object + * should be released with clang_disposeCXTUResourceUsage(). + */ +CINDEX_LINKAGE CXTUResourceUsage +clang_getCXTUResourceUsage(CXTranslationUnit TU); CINDEX_LINKAGE void clang_disposeCXTUResourceUsage(CXTUResourceUsage usage); @@ -1704,24 +1680,21 @@ clang_getTranslationUnitTargetInfo(CXTranslationUnit CTUnit); /** * Destroy the CXTargetInfo object. */ -CINDEX_LINKAGE void -clang_TargetInfo_dispose(CXTargetInfo Info); +CINDEX_LINKAGE void clang_TargetInfo_dispose(CXTargetInfo Info); /** * Get the normalized target triple as a string. * * Returns the empty string in case of any error. */ -CINDEX_LINKAGE CXString -clang_TargetInfo_getTriple(CXTargetInfo Info); +CINDEX_LINKAGE CXString clang_TargetInfo_getTriple(CXTargetInfo Info); /** * Get the pointer width of the target in bits. * * Returns -1 in case of error. */ -CINDEX_LINKAGE int -clang_TargetInfo_getPointerWidth(CXTargetInfo Info); +CINDEX_LINKAGE int clang_TargetInfo_getPointerWidth(CXTargetInfo Info); /** * @} @@ -1741,95 +1714,95 @@ enum CXCursorKind { * spelling, find their definitions, etc. However, the specific kind * of the declaration is not reported. */ - CXCursor_UnexposedDecl = 1, + CXCursor_UnexposedDecl = 1, /** A C or C++ struct. */ - CXCursor_StructDecl = 2, + CXCursor_StructDecl = 2, /** A C or C++ union. */ - CXCursor_UnionDecl = 3, + CXCursor_UnionDecl = 3, /** A C++ class. */ - CXCursor_ClassDecl = 4, + CXCursor_ClassDecl = 4, /** An enumeration. */ - CXCursor_EnumDecl = 5, + CXCursor_EnumDecl = 5, /** * A field (in C) or non-static data member (in C++) in a * struct, union, or C++ class. */ - CXCursor_FieldDecl = 6, + CXCursor_FieldDecl = 6, /** An enumerator constant. */ - CXCursor_EnumConstantDecl = 7, + CXCursor_EnumConstantDecl = 7, /** A function. */ - CXCursor_FunctionDecl = 8, + CXCursor_FunctionDecl = 8, /** A variable. */ - CXCursor_VarDecl = 9, + CXCursor_VarDecl = 9, /** A function or method parameter. */ - CXCursor_ParmDecl = 10, + CXCursor_ParmDecl = 10, /** An Objective-C \@interface. */ - CXCursor_ObjCInterfaceDecl = 11, + CXCursor_ObjCInterfaceDecl = 11, /** An Objective-C \@interface for a category. */ - CXCursor_ObjCCategoryDecl = 12, + CXCursor_ObjCCategoryDecl = 12, /** An Objective-C \@protocol declaration. */ - CXCursor_ObjCProtocolDecl = 13, + CXCursor_ObjCProtocolDecl = 13, /** An Objective-C \@property declaration. */ - CXCursor_ObjCPropertyDecl = 14, + CXCursor_ObjCPropertyDecl = 14, /** An Objective-C instance variable. */ - CXCursor_ObjCIvarDecl = 15, + CXCursor_ObjCIvarDecl = 15, /** An Objective-C instance method. */ - CXCursor_ObjCInstanceMethodDecl = 16, + CXCursor_ObjCInstanceMethodDecl = 16, /** An Objective-C class method. */ - CXCursor_ObjCClassMethodDecl = 17, + CXCursor_ObjCClassMethodDecl = 17, /** An Objective-C \@implementation. */ - CXCursor_ObjCImplementationDecl = 18, + CXCursor_ObjCImplementationDecl = 18, /** An Objective-C \@implementation for a category. */ - CXCursor_ObjCCategoryImplDecl = 19, + CXCursor_ObjCCategoryImplDecl = 19, /** A typedef. */ - CXCursor_TypedefDecl = 20, + CXCursor_TypedefDecl = 20, /** A C++ class method. */ - CXCursor_CXXMethod = 21, + CXCursor_CXXMethod = 21, /** A C++ namespace. */ - CXCursor_Namespace = 22, + CXCursor_Namespace = 22, /** A linkage specification, e.g. 'extern "C"'. */ - CXCursor_LinkageSpec = 23, + CXCursor_LinkageSpec = 23, /** A C++ constructor. */ - CXCursor_Constructor = 24, + CXCursor_Constructor = 24, /** A C++ destructor. */ - CXCursor_Destructor = 25, + CXCursor_Destructor = 25, /** A C++ conversion function. */ - CXCursor_ConversionFunction = 26, + CXCursor_ConversionFunction = 26, /** A C++ template type parameter. */ - CXCursor_TemplateTypeParameter = 27, + CXCursor_TemplateTypeParameter = 27, /** A C++ non-type template parameter. */ - CXCursor_NonTypeTemplateParameter = 28, + CXCursor_NonTypeTemplateParameter = 28, /** A C++ template template parameter. */ - CXCursor_TemplateTemplateParameter = 29, + CXCursor_TemplateTemplateParameter = 29, /** A C++ function template. */ - CXCursor_FunctionTemplate = 30, + CXCursor_FunctionTemplate = 30, /** A C++ class template. */ - CXCursor_ClassTemplate = 31, + CXCursor_ClassTemplate = 31, /** A C++ class template partial specialization. */ CXCursor_ClassTemplatePartialSpecialization = 32, /** A C++ namespace alias declaration. */ - CXCursor_NamespaceAlias = 33, + CXCursor_NamespaceAlias = 33, /** A C++ using directive. */ - CXCursor_UsingDirective = 34, + CXCursor_UsingDirective = 34, /** A C++ using declaration. */ - CXCursor_UsingDeclaration = 35, + CXCursor_UsingDeclaration = 35, /** A C++ alias declaration */ - CXCursor_TypeAliasDecl = 36, + CXCursor_TypeAliasDecl = 36, /** An Objective-C \@synthesize definition. */ - CXCursor_ObjCSynthesizeDecl = 37, + CXCursor_ObjCSynthesizeDecl = 37, /** An Objective-C \@dynamic definition. */ - CXCursor_ObjCDynamicDecl = 38, + CXCursor_ObjCDynamicDecl = 38, /** An access specifier. */ - CXCursor_CXXAccessSpecifier = 39, + CXCursor_CXXAccessSpecifier = 39, - CXCursor_FirstDecl = CXCursor_UnexposedDecl, - CXCursor_LastDecl = CXCursor_CXXAccessSpecifier, + CXCursor_FirstDecl = CXCursor_UnexposedDecl, + CXCursor_LastDecl = CXCursor_CXXAccessSpecifier, /* References */ - CXCursor_FirstRef = 40, /* Decl references */ - CXCursor_ObjCSuperClassRef = 40, - CXCursor_ObjCProtocolRef = 41, - CXCursor_ObjCClassRef = 42, + CXCursor_FirstRef = 40, /* Decl references */ + CXCursor_ObjCSuperClassRef = 40, + CXCursor_ObjCProtocolRef = 41, + CXCursor_ObjCClassRef = 42, /** * A reference to a type declaration. * @@ -1845,22 +1818,22 @@ enum CXCursorKind { * while the type of the variable "size" is referenced. The cursor * referenced by the type of size is the typedef for size_type. */ - CXCursor_TypeRef = 43, - CXCursor_CXXBaseSpecifier = 44, + CXCursor_TypeRef = 43, + CXCursor_CXXBaseSpecifier = 44, /** * A reference to a class template, function template, template * template parameter, or class template partial specialization. */ - CXCursor_TemplateRef = 45, + CXCursor_TemplateRef = 45, /** * A reference to a namespace or namespace alias. */ - CXCursor_NamespaceRef = 46, + CXCursor_NamespaceRef = 46, /** * A reference to a member of a struct, union, or class that occurs in * some non-expression context, e.g., a designated initializer. */ - CXCursor_MemberRef = 47, + CXCursor_MemberRef = 47, /** * A reference to a labeled statement. * @@ -1876,7 +1849,7 @@ enum CXCursorKind { * * A label reference cursor refers to a label statement. */ - CXCursor_LabelRef = 48, + CXCursor_LabelRef = 48, /** * A reference to a set of overloaded functions or function templates @@ -1914,26 +1887,26 @@ enum CXCursorKind { * \c clang_getOverloadedDecl() can be used to retrieve the definitions * referenced by this cursor. */ - CXCursor_OverloadedDeclRef = 49, + CXCursor_OverloadedDeclRef = 49, /** * A reference to a variable that occurs in some non-expression * context, e.g., a C++ lambda capture list. */ - CXCursor_VariableRef = 50, + CXCursor_VariableRef = 50, - CXCursor_LastRef = CXCursor_VariableRef, + CXCursor_LastRef = CXCursor_VariableRef, /* Error conditions */ - CXCursor_FirstInvalid = 70, - CXCursor_InvalidFile = 70, - CXCursor_NoDeclFound = 71, - CXCursor_NotImplemented = 72, - CXCursor_InvalidCode = 73, - CXCursor_LastInvalid = CXCursor_InvalidCode, + CXCursor_FirstInvalid = 70, + CXCursor_InvalidFile = 70, + CXCursor_NoDeclFound = 71, + CXCursor_NotImplemented = 72, + CXCursor_InvalidCode = 73, + CXCursor_LastInvalid = CXCursor_InvalidCode, /* Expressions */ - CXCursor_FirstExpr = 100, + CXCursor_FirstExpr = 100, /** * An expression whose specific kind is not exposed via this @@ -1944,104 +1917,104 @@ enum CXCursorKind { * spelling, children, etc. However, the specific kind of the * expression is not reported. */ - CXCursor_UnexposedExpr = 100, + CXCursor_UnexposedExpr = 100, /** * An expression that refers to some value declaration, such * as a function, variable, or enumerator. */ - CXCursor_DeclRefExpr = 101, + CXCursor_DeclRefExpr = 101, /** * An expression that refers to a member of a struct, union, * class, Objective-C class, etc. */ - CXCursor_MemberRefExpr = 102, + CXCursor_MemberRefExpr = 102, /** An expression that calls a function. */ - CXCursor_CallExpr = 103, + CXCursor_CallExpr = 103, /** An expression that sends a message to an Objective-C object or class. */ - CXCursor_ObjCMessageExpr = 104, + CXCursor_ObjCMessageExpr = 104, /** An expression that represents a block literal. */ - CXCursor_BlockExpr = 105, + CXCursor_BlockExpr = 105, /** An integer literal. */ - CXCursor_IntegerLiteral = 106, + CXCursor_IntegerLiteral = 106, /** A floating point number literal. */ - CXCursor_FloatingLiteral = 107, + CXCursor_FloatingLiteral = 107, /** An imaginary number literal. */ - CXCursor_ImaginaryLiteral = 108, + CXCursor_ImaginaryLiteral = 108, /** A string literal. */ - CXCursor_StringLiteral = 109, + CXCursor_StringLiteral = 109, /** A character literal. */ - CXCursor_CharacterLiteral = 110, + CXCursor_CharacterLiteral = 110, /** A parenthesized expression, e.g. "(1)". * * This AST node is only formed if full location information is requested. */ - CXCursor_ParenExpr = 111, + CXCursor_ParenExpr = 111, /** This represents the unary-expression's (except sizeof and * alignof). */ - CXCursor_UnaryOperator = 112, + CXCursor_UnaryOperator = 112, /** [C99 6.5.2.1] Array Subscripting. */ - CXCursor_ArraySubscriptExpr = 113, + CXCursor_ArraySubscriptExpr = 113, /** A builtin binary operation expression such as "x + y" or * "x <= y". */ - CXCursor_BinaryOperator = 114, + CXCursor_BinaryOperator = 114, /** Compound assignment such as "+=". */ - CXCursor_CompoundAssignOperator = 115, + CXCursor_CompoundAssignOperator = 115, /** The ?: ternary operator. */ - CXCursor_ConditionalOperator = 116, + CXCursor_ConditionalOperator = 116, /** An explicit cast in C (C99 6.5.4) or a C-style cast in C++ * (C++ [expr.cast]), which uses the syntax (Type)expr. * * For example: (int)f. */ - CXCursor_CStyleCastExpr = 117, + CXCursor_CStyleCastExpr = 117, /** [C99 6.5.2.5] */ - CXCursor_CompoundLiteralExpr = 118, + CXCursor_CompoundLiteralExpr = 118, /** Describes an C or C++ initializer list. */ - CXCursor_InitListExpr = 119, + CXCursor_InitListExpr = 119, /** The GNU address of label extension, representing &&label. */ - CXCursor_AddrLabelExpr = 120, + CXCursor_AddrLabelExpr = 120, /** This is the GNU Statement Expression extension: ({int X=4; X;}) */ - CXCursor_StmtExpr = 121, + CXCursor_StmtExpr = 121, /** Represents a C11 generic selection. */ - CXCursor_GenericSelectionExpr = 122, + CXCursor_GenericSelectionExpr = 122, /** Implements the GNU __null extension, which is a name for a null * pointer constant that has integral type (e.g., int or long) and is the same @@ -2051,23 +2024,23 @@ enum CXCursorKind { * NULL as __null in C++ rather than using 0 (which is an integer that may not * match the size of a pointer). */ - CXCursor_GNUNullExpr = 123, + CXCursor_GNUNullExpr = 123, /** C++'s static_cast<> expression. */ - CXCursor_CXXStaticCastExpr = 124, + CXCursor_CXXStaticCastExpr = 124, /** C++'s dynamic_cast<> expression. */ - CXCursor_CXXDynamicCastExpr = 125, + CXCursor_CXXDynamicCastExpr = 125, /** C++'s reinterpret_cast<> expression. */ - CXCursor_CXXReinterpretCastExpr = 126, + CXCursor_CXXReinterpretCastExpr = 126, /** C++'s const_cast<> expression. */ - CXCursor_CXXConstCastExpr = 127, + CXCursor_CXXConstCastExpr = 127, /** Represents an explicit C++ type conversion that uses "functional" * notion (C++ [expr.type.conv]). @@ -2077,60 +2050,60 @@ enum CXCursorKind { * x = int(0.5); * \endcode */ - CXCursor_CXXFunctionalCastExpr = 128, + CXCursor_CXXFunctionalCastExpr = 128, /** A C++ typeid expression (C++ [expr.typeid]). */ - CXCursor_CXXTypeidExpr = 129, + CXCursor_CXXTypeidExpr = 129, /** [C++ 2.13.5] C++ Boolean Literal. */ - CXCursor_CXXBoolLiteralExpr = 130, + CXCursor_CXXBoolLiteralExpr = 130, /** [C++0x 2.14.7] C++ Pointer Literal. */ - CXCursor_CXXNullPtrLiteralExpr = 131, + CXCursor_CXXNullPtrLiteralExpr = 131, /** Represents the "this" expression in C++ */ - CXCursor_CXXThisExpr = 132, + CXCursor_CXXThisExpr = 132, /** [C++ 15] C++ Throw Expression. * * This handles 'throw' and 'throw' assignment-expression. When * assignment-expression isn't present, Op will be null. */ - CXCursor_CXXThrowExpr = 133, + CXCursor_CXXThrowExpr = 133, /** A new expression for memory allocation and constructor calls, e.g: * "new CXXNewExpr(foo)". */ - CXCursor_CXXNewExpr = 134, + CXCursor_CXXNewExpr = 134, /** A delete expression for memory deallocation and destructor calls, * e.g. "delete[] pArray". */ - CXCursor_CXXDeleteExpr = 135, + CXCursor_CXXDeleteExpr = 135, /** A unary expression. (noexcept, sizeof, or other traits) */ - CXCursor_UnaryExpr = 136, + CXCursor_UnaryExpr = 136, /** An Objective-C string literal i.e. @"foo". */ - CXCursor_ObjCStringLiteral = 137, + CXCursor_ObjCStringLiteral = 137, /** An Objective-C \@encode expression. */ - CXCursor_ObjCEncodeExpr = 138, + CXCursor_ObjCEncodeExpr = 138, /** An Objective-C \@selector expression. */ - CXCursor_ObjCSelectorExpr = 139, + CXCursor_ObjCSelectorExpr = 139, /** An Objective-C \@protocol expression. */ - CXCursor_ObjCProtocolExpr = 140, + CXCursor_ObjCProtocolExpr = 140, /** An Objective-C "bridged" cast expression, which casts between * Objective-C pointers and C pointers, transferring ownership in the process. @@ -2139,7 +2112,7 @@ enum CXCursorKind { * NSString *str = (__bridge_transfer NSString *)CFCreateString(); * \endcode */ - CXCursor_ObjCBridgedCastExpr = 141, + CXCursor_ObjCBridgedCastExpr = 141, /** Represents a C++0x pack expansion that produces a sequence of * expressions. @@ -2154,7 +2127,7 @@ enum CXCursorKind { * } * \endcode */ - CXCursor_PackExpansionExpr = 142, + CXCursor_PackExpansionExpr = 142, /** Represents an expression that computes the length of a parameter * pack. @@ -2166,7 +2139,7 @@ enum CXCursorKind { * }; * \endcode */ - CXCursor_SizeOfPackExpr = 143, + CXCursor_SizeOfPackExpr = 143, /* Represents a C++ lambda expression that produces a local function * object. @@ -2180,33 +2153,42 @@ enum CXCursorKind { * } * \endcode */ - CXCursor_LambdaExpr = 144, + CXCursor_LambdaExpr = 144, /** Objective-c Boolean Literal. */ - CXCursor_ObjCBoolLiteralExpr = 145, + CXCursor_ObjCBoolLiteralExpr = 145, /** Represents the "self" expression in an Objective-C method. */ - CXCursor_ObjCSelfExpr = 146, + CXCursor_ObjCSelfExpr = 146, /** OpenMP 4.0 [2.4, Array Section]. */ - CXCursor_OMPArraySectionExpr = 147, + CXCursor_OMPArraySectionExpr = 147, /** Represents an @available(...) check. */ - CXCursor_ObjCAvailabilityCheckExpr = 148, + CXCursor_ObjCAvailabilityCheckExpr = 148, /** * Fixed point literal */ - CXCursor_FixedPointLiteral = 149, + CXCursor_FixedPointLiteral = 149, - CXCursor_LastExpr = CXCursor_FixedPointLiteral, + /** OpenMP 5.0 [2.1.4, Array Shaping]. + */ + CXCursor_OMPArrayShapingExpr = 150, + + /** + * OpenMP 5.0 [2.1.6 Iterators] + */ + CXCursor_OMPIteratorExpr = 151, + + CXCursor_LastExpr = CXCursor_OMPIteratorExpr, /* Statements */ - CXCursor_FirstStmt = 200, + CXCursor_FirstStmt = 200, /** * A statement whose specific kind is not exposed via this * interface. @@ -2216,7 +2198,7 @@ enum CXCursorKind { * children, etc. However, the specific kind of the statement is not * reported. */ - CXCursor_UnexposedStmt = 200, + CXCursor_UnexposedStmt = 200, /** A labelled statement in a function. * @@ -2229,226 +2211,226 @@ enum CXCursorKind { * \endcode * */ - CXCursor_LabelStmt = 201, + CXCursor_LabelStmt = 201, /** A group of statements like { stmt stmt }. * * This cursor kind is used to describe compound statements, e.g. function * bodies. */ - CXCursor_CompoundStmt = 202, + CXCursor_CompoundStmt = 202, /** A case statement. */ - CXCursor_CaseStmt = 203, + CXCursor_CaseStmt = 203, /** A default statement. */ - CXCursor_DefaultStmt = 204, + CXCursor_DefaultStmt = 204, /** An if statement */ - CXCursor_IfStmt = 205, + CXCursor_IfStmt = 205, /** A switch statement. */ - CXCursor_SwitchStmt = 206, + CXCursor_SwitchStmt = 206, /** A while statement. */ - CXCursor_WhileStmt = 207, + CXCursor_WhileStmt = 207, /** A do statement. */ - CXCursor_DoStmt = 208, + CXCursor_DoStmt = 208, /** A for statement. */ - CXCursor_ForStmt = 209, + CXCursor_ForStmt = 209, /** A goto statement. */ - CXCursor_GotoStmt = 210, + CXCursor_GotoStmt = 210, /** An indirect goto statement. */ - CXCursor_IndirectGotoStmt = 211, + CXCursor_IndirectGotoStmt = 211, /** A continue statement. */ - CXCursor_ContinueStmt = 212, + CXCursor_ContinueStmt = 212, /** A break statement. */ - CXCursor_BreakStmt = 213, + CXCursor_BreakStmt = 213, /** A return statement. */ - CXCursor_ReturnStmt = 214, + CXCursor_ReturnStmt = 214, /** A GCC inline assembly statement extension. */ - CXCursor_GCCAsmStmt = 215, - CXCursor_AsmStmt = CXCursor_GCCAsmStmt, + CXCursor_GCCAsmStmt = 215, + CXCursor_AsmStmt = CXCursor_GCCAsmStmt, /** Objective-C's overall \@try-\@catch-\@finally statement. */ - CXCursor_ObjCAtTryStmt = 216, + CXCursor_ObjCAtTryStmt = 216, /** Objective-C's \@catch statement. */ - CXCursor_ObjCAtCatchStmt = 217, + CXCursor_ObjCAtCatchStmt = 217, /** Objective-C's \@finally statement. */ - CXCursor_ObjCAtFinallyStmt = 218, + CXCursor_ObjCAtFinallyStmt = 218, /** Objective-C's \@throw statement. */ - CXCursor_ObjCAtThrowStmt = 219, + CXCursor_ObjCAtThrowStmt = 219, /** Objective-C's \@synchronized statement. */ - CXCursor_ObjCAtSynchronizedStmt = 220, + CXCursor_ObjCAtSynchronizedStmt = 220, /** Objective-C's autorelease pool statement. */ - CXCursor_ObjCAutoreleasePoolStmt = 221, + CXCursor_ObjCAutoreleasePoolStmt = 221, /** Objective-C's collection statement. */ - CXCursor_ObjCForCollectionStmt = 222, + CXCursor_ObjCForCollectionStmt = 222, /** C++'s catch statement. */ - CXCursor_CXXCatchStmt = 223, + CXCursor_CXXCatchStmt = 223, /** C++'s try statement. */ - CXCursor_CXXTryStmt = 224, + CXCursor_CXXTryStmt = 224, /** C++'s for (* : *) statement. */ - CXCursor_CXXForRangeStmt = 225, + CXCursor_CXXForRangeStmt = 225, /** Windows Structured Exception Handling's try statement. */ - CXCursor_SEHTryStmt = 226, + CXCursor_SEHTryStmt = 226, /** Windows Structured Exception Handling's except statement. */ - CXCursor_SEHExceptStmt = 227, + CXCursor_SEHExceptStmt = 227, /** Windows Structured Exception Handling's finally statement. */ - CXCursor_SEHFinallyStmt = 228, + CXCursor_SEHFinallyStmt = 228, /** A MS inline assembly statement extension. */ - CXCursor_MSAsmStmt = 229, + CXCursor_MSAsmStmt = 229, /** The null statement ";": C99 6.8.3p3. * * This cursor kind is used to describe the null statement. */ - CXCursor_NullStmt = 230, + CXCursor_NullStmt = 230, /** Adaptor class for mixing declarations with statements and * expressions. */ - CXCursor_DeclStmt = 231, + CXCursor_DeclStmt = 231, /** OpenMP parallel directive. */ - CXCursor_OMPParallelDirective = 232, + CXCursor_OMPParallelDirective = 232, /** OpenMP SIMD directive. */ - CXCursor_OMPSimdDirective = 233, + CXCursor_OMPSimdDirective = 233, /** OpenMP for directive. */ - CXCursor_OMPForDirective = 234, + CXCursor_OMPForDirective = 234, /** OpenMP sections directive. */ - CXCursor_OMPSectionsDirective = 235, + CXCursor_OMPSectionsDirective = 235, /** OpenMP section directive. */ - CXCursor_OMPSectionDirective = 236, + CXCursor_OMPSectionDirective = 236, /** OpenMP single directive. */ - CXCursor_OMPSingleDirective = 237, + CXCursor_OMPSingleDirective = 237, /** OpenMP parallel for directive. */ - CXCursor_OMPParallelForDirective = 238, + CXCursor_OMPParallelForDirective = 238, /** OpenMP parallel sections directive. */ - CXCursor_OMPParallelSectionsDirective = 239, + CXCursor_OMPParallelSectionsDirective = 239, /** OpenMP task directive. */ - CXCursor_OMPTaskDirective = 240, + CXCursor_OMPTaskDirective = 240, /** OpenMP master directive. */ - CXCursor_OMPMasterDirective = 241, + CXCursor_OMPMasterDirective = 241, /** OpenMP critical directive. */ - CXCursor_OMPCriticalDirective = 242, + CXCursor_OMPCriticalDirective = 242, /** OpenMP taskyield directive. */ - CXCursor_OMPTaskyieldDirective = 243, + CXCursor_OMPTaskyieldDirective = 243, /** OpenMP barrier directive. */ - CXCursor_OMPBarrierDirective = 244, + CXCursor_OMPBarrierDirective = 244, /** OpenMP taskwait directive. */ - CXCursor_OMPTaskwaitDirective = 245, + CXCursor_OMPTaskwaitDirective = 245, /** OpenMP flush directive. */ - CXCursor_OMPFlushDirective = 246, + CXCursor_OMPFlushDirective = 246, /** Windows Structured Exception Handling's leave statement. */ - CXCursor_SEHLeaveStmt = 247, + CXCursor_SEHLeaveStmt = 247, /** OpenMP ordered directive. */ - CXCursor_OMPOrderedDirective = 248, + CXCursor_OMPOrderedDirective = 248, /** OpenMP atomic directive. */ - CXCursor_OMPAtomicDirective = 249, + CXCursor_OMPAtomicDirective = 249, /** OpenMP for SIMD directive. */ - CXCursor_OMPForSimdDirective = 250, + CXCursor_OMPForSimdDirective = 250, /** OpenMP parallel for SIMD directive. */ - CXCursor_OMPParallelForSimdDirective = 251, + CXCursor_OMPParallelForSimdDirective = 251, /** OpenMP target directive. */ - CXCursor_OMPTargetDirective = 252, + CXCursor_OMPTargetDirective = 252, /** OpenMP teams directive. */ - CXCursor_OMPTeamsDirective = 253, + CXCursor_OMPTeamsDirective = 253, /** OpenMP taskgroup directive. */ - CXCursor_OMPTaskgroupDirective = 254, + CXCursor_OMPTaskgroupDirective = 254, /** OpenMP cancellation point directive. */ @@ -2456,35 +2438,35 @@ enum CXCursorKind { /** OpenMP cancel directive. */ - CXCursor_OMPCancelDirective = 256, + CXCursor_OMPCancelDirective = 256, /** OpenMP target data directive. */ - CXCursor_OMPTargetDataDirective = 257, + CXCursor_OMPTargetDataDirective = 257, /** OpenMP taskloop directive. */ - CXCursor_OMPTaskLoopDirective = 258, + CXCursor_OMPTaskLoopDirective = 258, /** OpenMP taskloop simd directive. */ - CXCursor_OMPTaskLoopSimdDirective = 259, + CXCursor_OMPTaskLoopSimdDirective = 259, /** OpenMP distribute directive. */ - CXCursor_OMPDistributeDirective = 260, + CXCursor_OMPDistributeDirective = 260, /** OpenMP target enter data directive. */ - CXCursor_OMPTargetEnterDataDirective = 261, + CXCursor_OMPTargetEnterDataDirective = 261, /** OpenMP target exit data directive. */ - CXCursor_OMPTargetExitDataDirective = 262, + CXCursor_OMPTargetExitDataDirective = 262, /** OpenMP target parallel directive. */ - CXCursor_OMPTargetParallelDirective = 263, + CXCursor_OMPTargetParallelDirective = 263, /** OpenMP target parallel for directive. */ @@ -2492,7 +2474,7 @@ enum CXCursorKind { /** OpenMP target update directive. */ - CXCursor_OMPTargetUpdateDirective = 265, + CXCursor_OMPTargetUpdateDirective = 265, /** OpenMP distribute parallel for directive. */ @@ -2564,23 +2546,23 @@ enum CXCursorKind { /** OpenMP master taskloop simd directive. */ - CXCursor_OMPMasterTaskLoopSimdDirective = 283, + CXCursor_OMPMasterTaskLoopSimdDirective = 283, /** OpenMP parallel master taskloop simd directive. */ - CXCursor_OMPParallelMasterTaskLoopSimdDirective = 284, + CXCursor_OMPParallelMasterTaskLoopSimdDirective = 284, /** OpenMP parallel master directive. */ - CXCursor_OMPParallelMasterDirective = 285, + CXCursor_OMPParallelMasterDirective = 285, /** OpenMP depobj directive. */ - CXCursor_OMPDepobjDirective = 286, + CXCursor_OMPDepobjDirective = 286, /** OpenMP scan directive. */ - CXCursor_OMPScanDirective = 287, + CXCursor_OMPScanDirective = 287, CXCursor_LastStmt = CXCursor_OMPScanDirective, @@ -2590,89 +2572,89 @@ enum CXCursorKind { * The translation unit cursor exists primarily to act as the root * cursor for traversing the contents of a translation unit. */ - CXCursor_TranslationUnit = 300, + CXCursor_TranslationUnit = 300, /* Attributes */ - CXCursor_FirstAttr = 400, + CXCursor_FirstAttr = 400, /** * An attribute whose specific kind is not exposed via this * interface. */ - CXCursor_UnexposedAttr = 400, - - CXCursor_IBActionAttr = 401, - CXCursor_IBOutletAttr = 402, - CXCursor_IBOutletCollectionAttr = 403, - CXCursor_CXXFinalAttr = 404, - CXCursor_CXXOverrideAttr = 405, - CXCursor_AnnotateAttr = 406, - CXCursor_AsmLabelAttr = 407, - CXCursor_PackedAttr = 408, - CXCursor_PureAttr = 409, - CXCursor_ConstAttr = 410, - CXCursor_NoDuplicateAttr = 411, - CXCursor_CUDAConstantAttr = 412, - CXCursor_CUDADeviceAttr = 413, - CXCursor_CUDAGlobalAttr = 414, - CXCursor_CUDAHostAttr = 415, - CXCursor_CUDASharedAttr = 416, - CXCursor_VisibilityAttr = 417, - CXCursor_DLLExport = 418, - CXCursor_DLLImport = 419, - CXCursor_NSReturnsRetained = 420, - CXCursor_NSReturnsNotRetained = 421, - CXCursor_NSReturnsAutoreleased = 422, - CXCursor_NSConsumesSelf = 423, - CXCursor_NSConsumed = 424, - CXCursor_ObjCException = 425, - CXCursor_ObjCNSObject = 426, - CXCursor_ObjCIndependentClass = 427, - CXCursor_ObjCPreciseLifetime = 428, - CXCursor_ObjCReturnsInnerPointer = 429, - CXCursor_ObjCRequiresSuper = 430, - CXCursor_ObjCRootClass = 431, - CXCursor_ObjCSubclassingRestricted = 432, - CXCursor_ObjCExplicitProtocolImpl = 433, - CXCursor_ObjCDesignatedInitializer = 434, - CXCursor_ObjCRuntimeVisible = 435, - CXCursor_ObjCBoxable = 436, - CXCursor_FlagEnum = 437, - CXCursor_ConvergentAttr = 438, - CXCursor_WarnUnusedAttr = 439, - CXCursor_WarnUnusedResultAttr = 440, - CXCursor_AlignedAttr = 441, - CXCursor_LastAttr = CXCursor_AlignedAttr, + CXCursor_UnexposedAttr = 400, + + CXCursor_IBActionAttr = 401, + CXCursor_IBOutletAttr = 402, + CXCursor_IBOutletCollectionAttr = 403, + CXCursor_CXXFinalAttr = 404, + CXCursor_CXXOverrideAttr = 405, + CXCursor_AnnotateAttr = 406, + CXCursor_AsmLabelAttr = 407, + CXCursor_PackedAttr = 408, + CXCursor_PureAttr = 409, + CXCursor_ConstAttr = 410, + CXCursor_NoDuplicateAttr = 411, + CXCursor_CUDAConstantAttr = 412, + CXCursor_CUDADeviceAttr = 413, + CXCursor_CUDAGlobalAttr = 414, + CXCursor_CUDAHostAttr = 415, + CXCursor_CUDASharedAttr = 416, + CXCursor_VisibilityAttr = 417, + CXCursor_DLLExport = 418, + CXCursor_DLLImport = 419, + CXCursor_NSReturnsRetained = 420, + CXCursor_NSReturnsNotRetained = 421, + CXCursor_NSReturnsAutoreleased = 422, + CXCursor_NSConsumesSelf = 423, + CXCursor_NSConsumed = 424, + CXCursor_ObjCException = 425, + CXCursor_ObjCNSObject = 426, + CXCursor_ObjCIndependentClass = 427, + CXCursor_ObjCPreciseLifetime = 428, + CXCursor_ObjCReturnsInnerPointer = 429, + CXCursor_ObjCRequiresSuper = 430, + CXCursor_ObjCRootClass = 431, + CXCursor_ObjCSubclassingRestricted = 432, + CXCursor_ObjCExplicitProtocolImpl = 433, + CXCursor_ObjCDesignatedInitializer = 434, + CXCursor_ObjCRuntimeVisible = 435, + CXCursor_ObjCBoxable = 436, + CXCursor_FlagEnum = 437, + CXCursor_ConvergentAttr = 438, + CXCursor_WarnUnusedAttr = 439, + CXCursor_WarnUnusedResultAttr = 440, + CXCursor_AlignedAttr = 441, + CXCursor_LastAttr = CXCursor_AlignedAttr, /* Preprocessing */ - CXCursor_PreprocessingDirective = 500, - CXCursor_MacroDefinition = 501, - CXCursor_MacroExpansion = 502, - CXCursor_MacroInstantiation = CXCursor_MacroExpansion, - CXCursor_InclusionDirective = 503, - CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective, - CXCursor_LastPreprocessing = CXCursor_InclusionDirective, + CXCursor_PreprocessingDirective = 500, + CXCursor_MacroDefinition = 501, + CXCursor_MacroExpansion = 502, + CXCursor_MacroInstantiation = CXCursor_MacroExpansion, + CXCursor_InclusionDirective = 503, + CXCursor_FirstPreprocessing = CXCursor_PreprocessingDirective, + CXCursor_LastPreprocessing = CXCursor_InclusionDirective, /* Extra Declarations */ /** * A module import declaration. */ - CXCursor_ModuleImportDecl = 600, - CXCursor_TypeAliasTemplateDecl = 601, + CXCursor_ModuleImportDecl = 600, + CXCursor_TypeAliasTemplateDecl = 601, /** * A static_assert or _Static_assert node */ - CXCursor_StaticAssert = 602, + CXCursor_StaticAssert = 602, /** * a friend declaration. */ - CXCursor_FriendDecl = 603, - CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl, - CXCursor_LastExtraDecl = CXCursor_FriendDecl, + CXCursor_FriendDecl = 603, + CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl, + CXCursor_LastExtraDecl = CXCursor_FriendDecl, /** * A code completion overload candidate. */ - CXCursor_OverloadCandidate = 700 + CXCursor_OverloadCandidate = 700 }; /** @@ -2943,14 +2925,10 @@ typedef struct CXPlatformAvailability { * platform-availability structures returned. There are * \c min(N, availability_size) such structures. */ -CINDEX_LINKAGE int -clang_getCursorPlatformAvailability(CXCursor cursor, - int *always_deprecated, - CXString *deprecated_message, - int *always_unavailable, - CXString *unavailable_message, - CXPlatformAvailability *availability, - int availability_size); +CINDEX_LINKAGE int clang_getCursorPlatformAvailability( + CXCursor cursor, int *always_deprecated, CXString *deprecated_message, + int *always_unavailable, CXString *unavailable_message, + CXPlatformAvailability *availability, int availability_size); /** * Free the memory associated with a \c CXPlatformAvailability structure. @@ -2977,11 +2955,7 @@ CINDEX_LINKAGE enum CXLanguageKind clang_getCursorLanguage(CXCursor cursor); * Describe the "thread-local storage (TLS) kind" of the declaration * referred to by a cursor. */ -enum CXTLSKind { - CXTLS_None = 0, - CXTLS_Dynamic, - CXTLS_Static -}; +enum CXTLSKind { CXTLS_None = 0, CXTLS_Dynamic, CXTLS_Static }; /** * Determine the "thread-local storage (TLS) kind" of the declaration @@ -3013,7 +2987,7 @@ CINDEX_LINKAGE void clang_disposeCXCursorSet(CXCursorSet cset); * Queries a CXCursorSet to see if it contains a specific CXCursor. * * \returns non-zero if the set contains the specified cursor. -*/ + */ CINDEX_LINKAGE unsigned clang_CXCursorSet_contains(CXCursorSet cset, CXCursor cursor); @@ -3021,7 +2995,7 @@ CINDEX_LINKAGE unsigned clang_CXCursorSet_contains(CXCursorSet cset, * Inserts a CXCursor into a CXCursorSet. * * \returns zero if the CXCursor was already in the set, and non-zero otherwise. -*/ + */ CINDEX_LINKAGE unsigned clang_CXCursorSet_insert(CXCursorSet cset, CXCursor cursor); @@ -3441,9 +3415,9 @@ CINDEX_LINKAGE CXType clang_getEnumDeclIntegerType(CXCursor C); * Retrieve the integer value of an enum constant declaration as a signed * long long. * - * If the cursor does not reference an enum constant declaration, LLONG_MIN is returned. - * Since this is also potentially a valid constant value, the kind of the cursor - * must be verified before calling this function. + * If the cursor does not reference an enum constant declaration, LLONG_MIN is + * returned. Since this is also potentially a valid constant value, the kind of + * the cursor must be verified before calling this function. */ CINDEX_LINKAGE long long clang_getEnumConstantDeclValue(CXCursor C); @@ -3451,11 +3425,12 @@ CINDEX_LINKAGE long long clang_getEnumConstantDeclValue(CXCursor C); * Retrieve the integer value of an enum constant declaration as an unsigned * long long. * - * If the cursor does not reference an enum constant declaration, ULLONG_MAX is returned. - * Since this is also potentially a valid constant value, the kind of the cursor - * must be verified before calling this function. + * If the cursor does not reference an enum constant declaration, ULLONG_MAX is + * returned. Since this is also potentially a valid constant value, the kind of + * the cursor must be verified before calling this function. */ -CINDEX_LINKAGE unsigned long long clang_getEnumConstantDeclUnsignedValue(CXCursor C); +CINDEX_LINKAGE unsigned long long +clang_getEnumConstantDeclUnsignedValue(CXCursor C); /** * Retrieve the bit width of a bit field declaration as an integer. @@ -3536,8 +3511,8 @@ CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C); * For I = 0, 1, and 2, Type, Integral, and Integral will be returned, * respectively. */ -CINDEX_LINKAGE enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind( - CXCursor C, unsigned I); +CINDEX_LINKAGE enum CXTemplateArgumentKind +clang_Cursor_getTemplateArgumentKind(CXCursor C, unsigned I); /** * Retrieve a CXType representing the type of a TemplateArgument of a @@ -3597,8 +3572,8 @@ CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C, * If called with I = 1 or 2, 2147483649 or true will be returned, respectively. * For I == 0, this function's behavior is undefined. */ -CINDEX_LINKAGE unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue( - CXCursor C, unsigned I); +CINDEX_LINKAGE unsigned long long +clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C, unsigned I); /** * Determine whether two CXTypes represent the same type. @@ -3783,7 +3758,8 @@ CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C); * Retrieve the exception specification type associated with a given cursor. * This is a value of type CXCursor_ExceptionSpecificationKind. * - * This only returns a valid result if the cursor refers to a function or method. + * This only returns a valid result if the cursor refers to a function or + * method. */ CINDEX_LINKAGE int clang_getCursorExceptionSpecificationType(CXCursor C); @@ -4011,7 +3987,8 @@ CINDEX_LINKAGE int clang_Type_getNumTemplateArguments(CXType T); * This function only returns template type arguments and does not handle * template template arguments or variadic packs. */ -CINDEX_LINKAGE CXType clang_Type_getTemplateArgumentAsType(CXType T, unsigned i); +CINDEX_LINKAGE CXType clang_Type_getTemplateArgumentAsType(CXType T, + unsigned i); /** * Retrieve the ref-qualifier kind of a function or method. @@ -4047,9 +4024,9 @@ enum CX_CXXAccessSpecifier { /** * Returns the access control level for the referenced object. * - * If the cursor refers to a C++ declaration, its access control level within its - * parent scope is returned. Otherwise, if the cursor refers to a base specifier or - * access specifier, the specifier itself is returned. + * If the cursor refers to a C++ declaration, its access control level within + * its parent scope is returned. Otherwise, if the cursor refers to a base + * specifier or access specifier, the specifier itself is returned. */ CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor); @@ -4200,7 +4177,7 @@ CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, CXCursorVisitor visitor, CXClientData client_data); #ifdef __has_feature -# if __has_feature(blocks) +#if __has_feature(blocks) /** * Visitor invoked for each cursor found by a traversal. * @@ -4211,16 +4188,16 @@ CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent, * The visitor should return one of the \c CXChildVisitResult values * to direct clang_visitChildrenWithBlock(). */ -typedef enum CXChildVisitResult - (^CXCursorVisitorBlock)(CXCursor cursor, CXCursor parent); +typedef enum CXChildVisitResult (^CXCursorVisitorBlock)(CXCursor cursor, + CXCursor parent); /** * Visits the children of a cursor using the specified block. Behaves * identically to clang_visitChildren() in all other respects. */ -CINDEX_LINKAGE unsigned clang_visitChildrenWithBlock(CXCursor parent, - CXCursorVisitorBlock block); -# endif +CINDEX_LINKAGE unsigned +clang_visitChildrenWithBlock(CXCursor parent, CXCursorVisitorBlock block); +#endif #endif /** @@ -4257,15 +4234,14 @@ CINDEX_LINKAGE CXString clang_constructUSR_ObjCClass(const char *class_name); /** * Construct a USR for a specified Objective-C category. */ -CINDEX_LINKAGE CXString - clang_constructUSR_ObjCCategory(const char *class_name, - const char *category_name); +CINDEX_LINKAGE CXString clang_constructUSR_ObjCCategory( + const char *class_name, const char *category_name); /** * Construct a USR for a specified Objective-C protocol. */ CINDEX_LINKAGE CXString - clang_constructUSR_ObjCProtocol(const char *protocol_name); +clang_constructUSR_ObjCProtocol(const char *protocol_name); /** * Construct a USR for a specified Objective-C instance variable and @@ -4305,9 +4281,8 @@ CINDEX_LINKAGE CXString clang_getCursorSpelling(CXCursor); * * \param options Reserved. */ -CINDEX_LINKAGE CXSourceRange clang_Cursor_getSpellingNameRange(CXCursor, - unsigned pieceIndex, - unsigned options); +CINDEX_LINKAGE CXSourceRange clang_Cursor_getSpellingNameRange( + CXCursor, unsigned pieceIndex, unsigned options); /** * Opaque pointer representing a policy that controls pretty printing @@ -4361,9 +4336,10 @@ clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy, /** * Set a property value for the given printing policy. */ -CINDEX_LINKAGE void clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy, - enum CXPrintingPolicyProperty Property, - unsigned Value); +CINDEX_LINKAGE void +clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy, + enum CXPrintingPolicyProperty Property, + unsigned Value); /** * Retrieve the default policy for the cursor. @@ -4511,18 +4487,18 @@ CINDEX_LINKAGE CXType clang_Cursor_getReceiverType(CXCursor C); * Property attributes for a \c CXCursor_ObjCPropertyDecl. */ typedef enum { - CXObjCPropertyAttr_noattr = 0x00, - CXObjCPropertyAttr_readonly = 0x01, - CXObjCPropertyAttr_getter = 0x02, - CXObjCPropertyAttr_assign = 0x04, + CXObjCPropertyAttr_noattr = 0x00, + CXObjCPropertyAttr_readonly = 0x01, + CXObjCPropertyAttr_getter = 0x02, + CXObjCPropertyAttr_assign = 0x04, CXObjCPropertyAttr_readwrite = 0x08, - CXObjCPropertyAttr_retain = 0x10, - CXObjCPropertyAttr_copy = 0x20, + CXObjCPropertyAttr_retain = 0x10, + CXObjCPropertyAttr_copy = 0x20, CXObjCPropertyAttr_nonatomic = 0x40, - CXObjCPropertyAttr_setter = 0x80, - CXObjCPropertyAttr_atomic = 0x100, - CXObjCPropertyAttr_weak = 0x200, - CXObjCPropertyAttr_strong = 0x400, + CXObjCPropertyAttr_setter = 0x80, + CXObjCPropertyAttr_atomic = 0x100, + CXObjCPropertyAttr_weak = 0x200, + CXObjCPropertyAttr_strong = 0x400, CXObjCPropertyAttr_unsafe_unretained = 0x800, CXObjCPropertyAttr_class = 0x1000 } CXObjCPropertyAttrKind; @@ -4534,8 +4510,8 @@ typedef enum { * * \param reserved Reserved for future use, pass 0. */ -CINDEX_LINKAGE unsigned clang_Cursor_getObjCPropertyAttributes(CXCursor C, - unsigned reserved); +CINDEX_LINKAGE unsigned +clang_Cursor_getObjCPropertyAttributes(CXCursor C, unsigned reserved); /** * Given a cursor that represents a property declaration, return the @@ -4597,8 +4573,9 @@ CINDEX_LINKAGE unsigned clang_Cursor_isVariadic(CXCursor C); * non-zero if the 'generated_declaration' is set in the attribute. */ CINDEX_LINKAGE unsigned clang_Cursor_isExternalSymbol(CXCursor C, - CXString *language, CXString *definedIn, - unsigned *isGenerated); + CXString *language, + CXString *definedIn, + unsigned *isGenerated); /** * Given a cursor that represents a declaration, return the associated @@ -4724,8 +4701,8 @@ CINDEX_LINKAGE unsigned clang_Module_getNumTopLevelHeaders(CXTranslationUnit, * \returns the specified top level header associated with the module. */ CINDEX_LINKAGE -CXFile clang_Module_getTopLevelHeader(CXTranslationUnit, - CXModule Module, unsigned Index); +CXFile clang_Module_getTopLevelHeader(CXTranslationUnit, CXModule Module, + unsigned Index); /** * @} @@ -4743,7 +4720,8 @@ CXFile clang_Module_getTopLevelHeader(CXTranslationUnit, /** * Determine if a C++ constructor is a converting constructor. */ -CINDEX_LINKAGE unsigned clang_CXXConstructor_isConvertingConstructor(CXCursor C); +CINDEX_LINKAGE unsigned +clang_CXXConstructor_isConvertingConstructor(CXCursor C); /** * Determine if a C++ constructor is a copy constructor. @@ -4873,9 +4851,8 @@ CINDEX_LINKAGE CXCursor clang_getSpecializedCursorTemplate(CXCursor C); * \returns The piece of the name pointed to by the given cursor. If there is no * name, or if the PieceIndex is out-of-range, a null-cursor will be returned. */ -CINDEX_LINKAGE CXSourceRange clang_getCursorReferenceNameRange(CXCursor C, - unsigned NameFlags, - unsigned PieceIndex); +CINDEX_LINKAGE CXSourceRange clang_getCursorReferenceNameRange( + CXCursor C, unsigned NameFlags, unsigned PieceIndex); enum CXNameRefFlags { /** @@ -5043,15 +5020,14 @@ CINDEX_LINKAGE void clang_tokenize(CXTranslationUnit TU, CXSourceRange Range, * \param Cursors an array of \p NumTokens cursors, whose contents will be * replaced with the cursors corresponding to each token. */ -CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens, - CXCursor *Cursors); +CINDEX_LINKAGE void clang_annotateTokens(CXTranslationUnit TU, CXToken *Tokens, + unsigned NumTokens, CXCursor *Cursors); /** * Free the given set of tokens. */ -CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, - CXToken *Tokens, unsigned NumTokens); +CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, CXToken *Tokens, + unsigned NumTokens); /** * @} @@ -5068,15 +5044,11 @@ CINDEX_LINKAGE void clang_disposeTokens(CXTranslationUnit TU, /* for debug/testing */ CINDEX_LINKAGE CXString clang_getCursorKindSpelling(enum CXCursorKind Kind); -CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent(CXCursor, - const char **startBuf, - const char **endBuf, - unsigned *startLine, - unsigned *startColumn, - unsigned *endLine, - unsigned *endColumn); +CINDEX_LINKAGE void clang_getDefinitionSpellingAndExtent( + CXCursor, const char **startBuf, const char **endBuf, unsigned *startLine, + unsigned *startColumn, unsigned *endLine, unsigned *endColumn); CINDEX_LINKAGE void clang_enableStackTraces(void); -CINDEX_LINKAGE void clang_executeOnThread(void (*fn)(void*), void *user_data, +CINDEX_LINKAGE void clang_executeOnThread(void (*fn)(void *), void *user_data, unsigned stack_size); /** @@ -5327,9 +5299,8 @@ clang_getCompletionChunkKind(CXCompletionString completion_string, * * \returns the text associated with the chunk at index \c chunk_number. */ -CINDEX_LINKAGE CXString -clang_getCompletionChunkText(CXCompletionString completion_string, - unsigned chunk_number); +CINDEX_LINKAGE CXString clang_getCompletionChunkText( + CXCompletionString completion_string, unsigned chunk_number); /** * Retrieve the completion string associated with a particular chunk @@ -5342,9 +5313,8 @@ clang_getCompletionChunkText(CXCompletionString completion_string, * \returns the completion string associated with the chunk at index * \c chunk_number. */ -CINDEX_LINKAGE CXCompletionString -clang_getCompletionChunkCompletionString(CXCompletionString completion_string, - unsigned chunk_number); +CINDEX_LINKAGE CXCompletionString clang_getCompletionChunkCompletionString( + CXCompletionString completion_string, unsigned chunk_number); /** * Retrieve the number of chunks in the given code-completion string. @@ -5401,9 +5371,8 @@ clang_getCompletionNumAnnotations(CXCompletionString completion_string); * \returns annotation string associated with the completion at index * \c annotation_number, or a NULL string if that annotation is not available. */ -CINDEX_LINKAGE CXString -clang_getCompletionAnnotation(CXCompletionString completion_string, - unsigned annotation_number); +CINDEX_LINKAGE CXString clang_getCompletionAnnotation( + CXCompletionString completion_string, unsigned annotation_number); /** * Retrieve the parent context of the given completion string. @@ -5421,9 +5390,8 @@ clang_getCompletionAnnotation(CXCompletionString completion_string, * \returns The name of the completion parent, e.g., "NSObject" if * the completion string represents a method in the NSObject class. */ -CINDEX_LINKAGE CXString -clang_getCompletionParent(CXCompletionString completion_string, - enum CXCursorKind *kind); +CINDEX_LINKAGE CXString clang_getCompletionParent( + CXCompletionString completion_string, enum CXCursorKind *kind); /** * Retrieve the brief documentation comment attached to the declaration @@ -5779,13 +5747,11 @@ CINDEX_LINKAGE unsigned clang_defaultCodeCompleteOptions(void); * completion fails, returns NULL. */ CINDEX_LINKAGE -CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, - const char *complete_filename, - unsigned complete_line, - unsigned complete_column, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - unsigned options); +CXCodeCompleteResults * +clang_codeCompleteAt(CXTranslationUnit TU, const char *complete_filename, + unsigned complete_line, unsigned complete_column, + struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, unsigned options); /** * Sort the code-completion results in case-insensitive alphabetical @@ -5834,8 +5800,8 @@ CXDiagnostic clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *Results, * along with the given code completion results. */ CINDEX_LINKAGE -unsigned long long clang_codeCompleteGetContexts( - CXCodeCompleteResults *Results); +unsigned long long +clang_codeCompleteGetContexts(CXCodeCompleteResults *Results); /** * Returns the cursor kind for the container for the current code @@ -5854,9 +5820,9 @@ unsigned long long clang_codeCompleteGetContexts( * container */ CINDEX_LINKAGE -enum CXCursorKind clang_codeCompleteGetContainerKind( - CXCodeCompleteResults *Results, - unsigned *IsIncomplete); +enum CXCursorKind +clang_codeCompleteGetContainerKind(CXCodeCompleteResults *Results, + unsigned *IsIncomplete); /** * Returns the USR for the container for the current code completion @@ -5908,19 +5874,19 @@ CINDEX_LINKAGE CXString clang_getClangVersion(void); */ CINDEX_LINKAGE void clang_toggleCrashRecovery(unsigned isEnabled); - /** - * Visitor invoked for each file in a translation unit - * (used with clang_getInclusions()). - * - * This visitor function will be invoked by clang_getInclusions() for each - * file included (either at the top-level or by \#include directives) within - * a translation unit. The first argument is the file being included, and - * the second and third arguments provide the inclusion stack. The - * array is sorted in order of immediate inclusion. For example, - * the first element refers to the location that included 'included_file'. - */ +/** + * Visitor invoked for each file in a translation unit + * (used with clang_getInclusions()). + * + * This visitor function will be invoked by clang_getInclusions() for each + * file included (either at the top-level or by \#include directives) within + * a translation unit. The first argument is the file being included, and + * the second and third arguments provide the inclusion stack. The + * array is sorted in order of immediate inclusion. For example, + * the first element refers to the location that included 'included_file'. + */ typedef void (*CXInclusionVisitor)(CXFile included_file, - CXSourceLocation* inclusion_stack, + CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data); @@ -5935,7 +5901,7 @@ CINDEX_LINKAGE void clang_getInclusions(CXTranslationUnit tu, CXClientData client_data); typedef enum { - CXEval_Int = 1 , + CXEval_Int = 1, CXEval_Float = 2, CXEval_ObjCStrLiteral = 3, CXEval_StrLiteral = 4, @@ -5944,12 +5910,12 @@ typedef enum { CXEval_UnExposed = 0 -} CXEvalResultKind ; +} CXEvalResultKind; /** * Evaluation result of a cursor */ -typedef void * CXEvalResult; +typedef void *CXEvalResult; /** * If cursor is a statement declaration tries to evaluate the @@ -5986,7 +5952,8 @@ CINDEX_LINKAGE unsigned clang_EvalResult_isUnsignedInt(CXEvalResult E); * Returns the evaluation result as an unsigned integer if * the kind is Int and clang_EvalResult_isUnsignedInt is non-zero. */ -CINDEX_LINKAGE unsigned long long clang_EvalResult_getAsUnsigned(CXEvalResult E); +CINDEX_LINKAGE unsigned long long +clang_EvalResult_getAsUnsigned(CXEvalResult E); /** * Returns the evaluation result as double if the @@ -6000,7 +5967,7 @@ CINDEX_LINKAGE double clang_EvalResult_getAsDouble(CXEvalResult E); * instead call clang_EvalResult_dispose on the CXEvalResult returned * by clang_Cursor_Evaluate. */ -CINDEX_LINKAGE const char* clang_EvalResult_getAsStr(CXEvalResult E); +CINDEX_LINKAGE const char *clang_EvalResult_getAsStr(CXEvalResult E); /** * Disposes the created Eval memory. @@ -6058,7 +6025,8 @@ CINDEX_LINKAGE unsigned clang_remap_getNumFiles(CXRemapping); * is associated with. */ CINDEX_LINKAGE void clang_remap_getFilenames(CXRemapping, unsigned index, - CXString *original, CXString *transformed); + CXString *original, + CXString *transformed); /** * Dispose the remapping. @@ -6074,10 +6042,7 @@ CINDEX_LINKAGE void clang_remap_dispose(CXRemapping); * @{ */ -enum CXVisitorResult { - CXVisit_Break, - CXVisit_Continue -}; +enum CXVisitorResult { CXVisit_Break, CXVisit_Continue }; typedef struct CXCursorAndRangeVisitor { void *context; @@ -6115,8 +6080,8 @@ typedef enum { * * \returns one of the CXResult enumerators. */ -CINDEX_LINKAGE CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file, - CXCursorAndRangeVisitor visitor); +CINDEX_LINKAGE CXResult clang_findReferencesInFile( + CXCursor cursor, CXFile file, CXCursorAndRangeVisitor visitor); /** * Find #import/#include directives in a specific file. @@ -6130,15 +6095,14 @@ CINDEX_LINKAGE CXResult clang_findReferencesInFile(CXCursor cursor, CXFile file, * * \returns one of the CXResult enumerators. */ -CINDEX_LINKAGE CXResult clang_findIncludesInFile(CXTranslationUnit TU, - CXFile file, - CXCursorAndRangeVisitor visitor); +CINDEX_LINKAGE CXResult clang_findIncludesInFile( + CXTranslationUnit TU, CXFile file, CXCursorAndRangeVisitor visitor); #ifdef __has_feature -# if __has_feature(blocks) +#if __has_feature(blocks) -typedef enum CXVisitorResult - (^CXCursorAndRangeVisitorBlock)(CXCursor, CXSourceRange); +typedef enum CXVisitorResult (^CXCursorAndRangeVisitorBlock)(CXCursor, + CXSourceRange); CINDEX_LINKAGE CXResult clang_findReferencesInFileWithBlock(CXCursor, CXFile, @@ -6148,7 +6112,7 @@ CINDEX_LINKAGE CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile, CXCursorAndRangeVisitorBlock); -# endif +#endif #endif /** @@ -6231,46 +6195,46 @@ typedef struct { } CXIdxImportedASTFileInfo; typedef enum { - CXIdxEntity_Unexposed = 0, - CXIdxEntity_Typedef = 1, - CXIdxEntity_Function = 2, - CXIdxEntity_Variable = 3, - CXIdxEntity_Field = 4, - CXIdxEntity_EnumConstant = 5, + CXIdxEntity_Unexposed = 0, + CXIdxEntity_Typedef = 1, + CXIdxEntity_Function = 2, + CXIdxEntity_Variable = 3, + CXIdxEntity_Field = 4, + CXIdxEntity_EnumConstant = 5, - CXIdxEntity_ObjCClass = 6, - CXIdxEntity_ObjCProtocol = 7, - CXIdxEntity_ObjCCategory = 8, + CXIdxEntity_ObjCClass = 6, + CXIdxEntity_ObjCProtocol = 7, + CXIdxEntity_ObjCCategory = 8, CXIdxEntity_ObjCInstanceMethod = 9, - CXIdxEntity_ObjCClassMethod = 10, - CXIdxEntity_ObjCProperty = 11, - CXIdxEntity_ObjCIvar = 12, - - CXIdxEntity_Enum = 13, - CXIdxEntity_Struct = 14, - CXIdxEntity_Union = 15, - - CXIdxEntity_CXXClass = 16, - CXIdxEntity_CXXNamespace = 17, - CXIdxEntity_CXXNamespaceAlias = 18, - CXIdxEntity_CXXStaticVariable = 19, - CXIdxEntity_CXXStaticMethod = 20, - CXIdxEntity_CXXInstanceMethod = 21, - CXIdxEntity_CXXConstructor = 22, - CXIdxEntity_CXXDestructor = 23, + CXIdxEntity_ObjCClassMethod = 10, + CXIdxEntity_ObjCProperty = 11, + CXIdxEntity_ObjCIvar = 12, + + CXIdxEntity_Enum = 13, + CXIdxEntity_Struct = 14, + CXIdxEntity_Union = 15, + + CXIdxEntity_CXXClass = 16, + CXIdxEntity_CXXNamespace = 17, + CXIdxEntity_CXXNamespaceAlias = 18, + CXIdxEntity_CXXStaticVariable = 19, + CXIdxEntity_CXXStaticMethod = 20, + CXIdxEntity_CXXInstanceMethod = 21, + CXIdxEntity_CXXConstructor = 22, + CXIdxEntity_CXXDestructor = 23, CXIdxEntity_CXXConversionFunction = 24, - CXIdxEntity_CXXTypeAlias = 25, - CXIdxEntity_CXXInterface = 26 + CXIdxEntity_CXXTypeAlias = 25, + CXIdxEntity_CXXInterface = 26 } CXIdxEntityKind; typedef enum { CXIdxEntityLang_None = 0, - CXIdxEntityLang_C = 1, + CXIdxEntityLang_C = 1, CXIdxEntityLang_ObjC = 2, - CXIdxEntityLang_CXX = 3, - CXIdxEntityLang_Swift = 4 + CXIdxEntityLang_CXX = 3, + CXIdxEntityLang_Swift = 4 } CXIdxEntityLanguage; /** @@ -6284,16 +6248,16 @@ typedef enum { * CXIdxEntity_CXXTypeAlias */ typedef enum { - CXIdxEntity_NonTemplate = 0, - CXIdxEntity_Template = 1, + CXIdxEntity_NonTemplate = 0, + CXIdxEntity_Template = 1, CXIdxEntity_TemplatePartialSpecialization = 2, CXIdxEntity_TemplateSpecialization = 3 } CXIdxEntityCXXTemplateKind; typedef enum { - CXIdxAttr_Unexposed = 0, - CXIdxAttr_IBAction = 1, - CXIdxAttr_IBOutlet = 2, + CXIdxAttr_Unexposed = 0, + CXIdxAttr_IBAction = 1, + CXIdxAttr_IBOutlet = 2, CXIdxAttr_IBOutletCollection = 3 } CXIdxAttrKind; @@ -6325,9 +6289,7 @@ typedef struct { CXIdxLoc classLoc; } CXIdxIBOutletCollectionAttrInfo; -typedef enum { - CXIdxDeclFlag_Skipped = 0x1 -} CXIdxDeclInfoFlags; +typedef enum { CXIdxDeclFlag_Skipped = 0x1 } CXIdxDeclInfoFlags; typedef struct { const CXIdxEntityInfo *entityInfo; @@ -6496,11 +6458,10 @@ typedef struct { /** * Called at the end of indexing; passes the complete diagnostic set. */ - void (*diagnostic)(CXClientData client_data, - CXDiagnosticSet, void *reserved); + void (*diagnostic)(CXClientData client_data, CXDiagnosticSet, void *reserved); - CXIdxClientFile (*enteredMainFile)(CXClientData client_data, - CXFile mainFile, void *reserved); + CXIdxClientFile (*enteredMainFile)(CXClientData client_data, CXFile mainFile, + void *reserved); /** * Called when a file gets \#included/\#imported. @@ -6525,8 +6486,7 @@ typedef struct { CXIdxClientContainer (*startedTranslationUnit)(CXClientData client_data, void *reserved); - void (*indexDeclaration)(CXClientData client_data, - const CXIdxDeclInfo *); + void (*indexDeclaration)(CXClientData client_data, const CXIdxDeclInfo *); /** * Called to index a reference of an entity. @@ -6570,8 +6530,8 @@ clang_index_getClientContainer(const CXIdxContainerInfo *); * For setting a custom CXIdxClientContainer attached to a * container. */ -CINDEX_LINKAGE void -clang_index_setClientContainer(const CXIdxContainerInfo *,CXIdxClientContainer); +CINDEX_LINKAGE void clang_index_setClientContainer(const CXIdxContainerInfo *, + CXIdxClientContainer); /** * For retrieving a custom CXIdxClientEntity attached to an entity. @@ -6582,8 +6542,8 @@ clang_index_getClientEntity(const CXIdxEntityInfo *); /** * For setting a custom CXIdxClientEntity attached to an entity. */ -CINDEX_LINKAGE void -clang_index_setClientEntity(const CXIdxEntityInfo *, CXIdxClientEntity); +CINDEX_LINKAGE void clang_index_setClientEntity(const CXIdxEntityInfo *, + CXIdxClientEntity); /** * An indexing action/session, to be applied to one or multiple @@ -6671,18 +6631,12 @@ typedef enum { * * The rest of the parameters are the same as #clang_parseTranslationUnit. */ -CINDEX_LINKAGE int clang_indexSourceFile(CXIndexAction, - CXClientData client_data, - IndexerCallbacks *index_callbacks, - unsigned index_callbacks_size, - unsigned index_options, - const char *source_filename, - const char * const *command_line_args, - int num_command_line_args, - struct CXUnsavedFile *unsaved_files, - unsigned num_unsaved_files, - CXTranslationUnit *out_TU, - unsigned TU_options); +CINDEX_LINKAGE int clang_indexSourceFile( + CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, unsigned index_options, + const char *source_filename, const char *const *command_line_args, + int num_command_line_args, struct CXUnsavedFile *unsaved_files, + unsigned num_unsaved_files, CXTranslationUnit *out_TU, unsigned TU_options); /** * Same as clang_indexSourceFile but requires a full command line @@ -6712,12 +6666,9 @@ CINDEX_LINKAGE int clang_indexSourceFileFullArgv( * \returns If there is a failure from which there is no recovery, returns * non-zero, otherwise returns 0. */ -CINDEX_LINKAGE int clang_indexTranslationUnit(CXIndexAction, - CXClientData client_data, - IndexerCallbacks *index_callbacks, - unsigned index_callbacks_size, - unsigned index_options, - CXTranslationUnit); +CINDEX_LINKAGE int clang_indexTranslationUnit( + CXIndexAction, CXClientData client_data, IndexerCallbacks *index_callbacks, + unsigned index_callbacks_size, unsigned index_options, CXTranslationUnit); /** * Retrieve the CXIdxFile, file, line, column, and offset represented by @@ -6729,8 +6680,7 @@ CINDEX_LINKAGE int clang_indexTranslationUnit(CXIndexAction, */ CINDEX_LINKAGE void clang_indexLoc_getFileLocation(CXIdxLoc loc, CXIdxClientFile *indexFile, - CXFile *file, - unsigned *line, + CXFile *file, unsigned *line, unsigned *column, unsigned *offset); @@ -6773,8 +6723,7 @@ typedef enum CXVisitorResult (*CXFieldVisitor)(CXCursor C, * \returns a non-zero value if the traversal was terminated * prematurely by the visitor returning \c CXFieldVisit_Break. */ -CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T, - CXFieldVisitor visitor, +CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T, CXFieldVisitor visitor, CXClientData client_data); /** diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index ca0f991c24e31..6813ab58874ee 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -970,7 +970,7 @@ class ASTContext : public RefCountedBase { #include "clang/Basic/OpenCLImageTypes.def" CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; CanQualType OCLQueueTy, OCLReserveIDTy; - CanQualType OMPArraySectionTy; + CanQualType OMPArraySectionTy, OMPArrayShapingTy, OMPIteratorTy; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ CanQualType Id##Ty; #include "clang/Basic/OpenCLExtensionTypes.def" diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 5f6035cb0c282..735056e2a31e0 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -16,10 +16,11 @@ #include "clang/AST/ASTFwd.h" #include "clang/AST/AttrIterator.h" #include "clang/AST/Decl.h" -#include "clang/AST/OpenMPClause.h" +#include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/Basic/AttrKinds.h" #include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/Sanitizers.h" @@ -40,6 +41,7 @@ class Expr; class QualType; class FunctionDecl; class TypeSourceInfo; +class OMPTraitInfo; /// Attr - This represents one attribute. class Attr : public AttributeCommonInfo { diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def index 74a45ee4ccc0f..f8eb4ec19c8f1 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -313,8 +313,14 @@ PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy) // A placeholder type for OpenMP array sections. PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy) +// A placeholder type for OpenMP array shaping operation. +PLACEHOLDER_TYPE(OMPArrayShaping, OMPArrayShapingTy) + +// A placeholder type for OpenMP iterators. +PLACEHOLDER_TYPE(OMPIterator, OMPIteratorTy) + #ifdef LAST_BUILTIN_TYPE -LAST_BUILTIN_TYPE(OMPArraySection) +LAST_BUILTIN_TYPE(OMPIterator) #undef LAST_BUILTIN_TYPE #endif diff --git a/clang/include/clang/AST/ComputeDependence.h b/clang/include/clang/AST/ComputeDependence.h index 02f826438d4df..ab742c9b70ddf 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -87,6 +87,8 @@ class ParenListExpr; class PseudoObjectExpr; class AtomicExpr; class OMPArraySectionExpr; +class OMPArrayShapingExpr; +class OMPIteratorExpr; class ObjCArrayLiteral; class ObjCDictionaryLiteral; class ObjCBoxedExpr; @@ -172,6 +174,8 @@ ExprDependence computeDependence(PseudoObjectExpr *E); ExprDependence computeDependence(AtomicExpr *E); ExprDependence computeDependence(OMPArraySectionExpr *E); +ExprDependence computeDependence(OMPArrayShapingExpr *E); +ExprDependence computeDependence(OMPIteratorExpr *E); ExprDependence computeDependence(ObjCArrayLiteral *E); ExprDependence computeDependence(ObjCDictionaryLiteral *E); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 0ce8b852b2ff3..2af1189511a30 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2030,7 +2030,7 @@ class FunctionDecl : public DeclaratorDecl, /// declaration to the declaration that is a definition (if there is one). bool isDefined(const FunctionDecl *&Definition) const; - virtual bool isDefined() const { + bool isDefined() const { const FunctionDecl* Definition; return isDefined(Definition); } @@ -4542,6 +4542,13 @@ inline bool IsEnumDeclScoped(EnumDecl *ED) { return ED->isScoped(); } +/// OpenMP variants are mangled early based on their OpenMP context selector. +/// The new name looks likes this: +/// + OpenMPVariantManglingSeparatorStr + +static constexpr StringRef getOpenMPVariantManglingSeparatorStr() { + return ".ompvariant"; +} + } // namespace clang #endif // LLVM_CLANG_AST_DECL_H diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index 788227156c4d9..0b24bae6df9b1 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -36,7 +36,6 @@ struct ExprDependenceScope { }; }; using ExprDependence = ExprDependenceScope::ExprDependence; -static constexpr unsigned ExprDependenceBits = 5; struct TypeDependenceScope { enum TypeDependence : uint8_t { @@ -51,18 +50,19 @@ struct TypeDependenceScope { /// Whether this type is a variably-modified type (C99 6.7.5). VariablyModified = 8, - // FIXME: add Error bit. + /// Whether this type references an error, e.g. decltype(err-expression) + /// yields an error type. + Error = 16, None = 0, - All = 15, + All = 31, DependentInstantiation = Dependent | Instantiation, - LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/VariablyModified) + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Error) }; }; using TypeDependence = TypeDependenceScope::TypeDependence; -static constexpr unsigned TypeDependenceBits = 4; #define LLVM_COMMON_DEPENDENCE(NAME) \ struct NAME##Scope { \ @@ -78,37 +78,134 @@ static constexpr unsigned TypeDependenceBits = 4; LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/Dependent) \ }; \ }; \ - using NAME = NAME##Scope::NAME; \ - static constexpr unsigned NAME##Bits = 3; + using NAME = NAME##Scope::NAME; LLVM_COMMON_DEPENDENCE(NestedNameSpecifierDependence) LLVM_COMMON_DEPENDENCE(TemplateNameDependence) LLVM_COMMON_DEPENDENCE(TemplateArgumentDependence) #undef LLVM_COMMON_DEPENDENCE +// A combined space of all dependence concepts for all node types. +// Used when aggregating dependence of nodes of different types. +class Dependence { +public: + enum Bits : uint8_t { + None = 0, + + // Contains a template parameter pack that wasn't expanded. + UnexpandedPack = 1, + // Uses a template parameter, even if it doesn't affect the result. + // Validity depends on the template parameter. + Instantiation = 2, + // Expression type depends on template context. + // Value and Instantiation should also be set. + Type = 4, + // Expression value depends on template context. + // Instantiation should also be set. + Value = 8, + // Depends on template context. + // The type/value distinction is only meaningful for expressions. + Dependent = Type | Value, + // Includes an error, and depends on how it is resolved. + Error = 16, + // Type depends on a runtime value (variable-length array). + VariablyModified = 32, + + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/VariablyModified) + }; + + Dependence() : V(None) {} + + Dependence(TypeDependence D) + : V(translate(D, TypeDependence::UnexpandedPack, UnexpandedPack) | + translate(D, TypeDependence::Instantiation, Instantiation) | + translate(D, TypeDependence::Dependent, Dependent) | + translate(D, TypeDependence::VariablyModified, VariablyModified)) { + } + + Dependence(ExprDependence D) + : V(translate(D, ExprDependence::UnexpandedPack, UnexpandedPack) | + translate(D, ExprDependence::Instantiation, Instantiation) | + translate(D, ExprDependence::Type, Type) | + translate(D, ExprDependence::Value, Value) | + translate(D, ExprDependence::Error, Error)) {} + + Dependence(NestedNameSpecifierDependence D) : + V ( translate(D, NNSDependence::UnexpandedPack, UnexpandedPack) | + translate(D, NNSDependence::Instantiation, Instantiation) | + translate(D, NNSDependence::Dependent, Dependent)){} + + Dependence(TemplateArgumentDependence D) + : V(translate(D, TADependence::UnexpandedPack, UnexpandedPack) | + translate(D, TADependence::Instantiation, Instantiation) | + translate(D, TADependence::Dependent, Dependent)) {} + + Dependence(TemplateNameDependence D) + : V(translate(D, TNDependence::UnexpandedPack, UnexpandedPack) | + translate(D, TNDependence::Instantiation, Instantiation) | + translate(D, TNDependence::Dependent, Dependent)) {} + + TypeDependence type() const { + return translate(V, UnexpandedPack, TypeDependence::UnexpandedPack) | + translate(V, Instantiation, TypeDependence::Instantiation) | + translate(V, Dependent, TypeDependence::Dependent) | + translate(V, Error, TypeDependence::Error) | + translate(V, VariablyModified, TypeDependence::VariablyModified); + } + + ExprDependence expr() const { + return translate(V, UnexpandedPack, ExprDependence::UnexpandedPack) | + translate(V, Instantiation, ExprDependence::Instantiation) | + translate(V, Type, ExprDependence::Type) | + translate(V, Value, ExprDependence::Value) | + translate(V, Error, ExprDependence::Error); + } + + NestedNameSpecifierDependence nestedNameSpecifier() const { + return translate(V, UnexpandedPack, NNSDependence::UnexpandedPack) | + translate(V, Instantiation, NNSDependence::Instantiation) | + translate(V, Dependent, NNSDependence::Dependent); + } + + TemplateArgumentDependence templateArgument() const { + return translate(V, UnexpandedPack, TADependence::UnexpandedPack) | + translate(V, Instantiation, TADependence::Instantiation) | + translate(V, Dependent, TADependence::Dependent); + } + + TemplateNameDependence templateName() const { + return translate(V, UnexpandedPack, TNDependence::UnexpandedPack) | + translate(V, Instantiation, TNDependence::Instantiation) | + translate(V, Dependent, TNDependence::Dependent); + } + +private: + Bits V; + + template + static U translate(T Bits, T FromBit, U ToBit) { + return (Bits & FromBit) ? ToBit : static_cast(0); + } + + // Abbreviations to make conversions more readable. + using NNSDependence = NestedNameSpecifierDependence; + using TADependence = TemplateArgumentDependence; + using TNDependence = TemplateNameDependence; +}; + /// Computes dependencies of a reference with the name having template arguments /// with \p TA dependencies. inline ExprDependence toExprDependence(TemplateArgumentDependence TA) { - auto D = ExprDependence::None; - if (TA & TemplateArgumentDependence::UnexpandedPack) - D |= ExprDependence::UnexpandedPack; - if (TA & TemplateArgumentDependence::Instantiation) - D |= ExprDependence::Instantiation; - if (TA & TemplateArgumentDependence::Dependent) - D |= ExprDependence::Type | ExprDependence::Value; - return D; + return Dependence(TA).expr(); } -inline ExprDependence toExprDependence(TypeDependence TD) { - // This hack works because TypeDependence and TemplateArgumentDependence - // share the same bit representation, apart from variably-modified. - return toExprDependence(static_cast( - TD & ~TypeDependence::VariablyModified)); +inline ExprDependence toExprDependence(TypeDependence D) { + return Dependence(D).expr(); } -inline ExprDependence toExprDependence(NestedNameSpecifierDependence NSD) { - // This hack works because TypeDependence and TemplateArgumentDependence - // share the same bit representation. - return toExprDependence(static_cast(NSD)) & - ~ExprDependence::TypeValue; +// Note: it's often necessary to strip `Dependent` from qualifiers. +// If V:: refers to the current instantiation, NNS is considered dependent +// but the containing V::foo likely isn't. +inline ExprDependence toExprDependence(NestedNameSpecifierDependence D) { + return Dependence(D).expr(); } inline ExprDependence turnTypeToValueDependence(ExprDependence D) { // Type-dependent expressions are always be value-dependent, so we simply drop @@ -124,57 +221,39 @@ inline ExprDependence turnValueToTypeDependence(ExprDependence D) { // Returned type-dependence will never have VariablyModified set. inline TypeDependence toTypeDependence(ExprDependence D) { - // Supported bits all have the same representation. - return static_cast(D & (ExprDependence::UnexpandedPack | - ExprDependence::Instantiation | - ExprDependence::Type)); + return Dependence(D).type(); } inline TypeDependence toTypeDependence(NestedNameSpecifierDependence D) { - // Supported bits all have the same representation. - return static_cast(D); + return Dependence(D).type(); } inline TypeDependence toTypeDependence(TemplateNameDependence D) { - // Supported bits all have the same representation. - return static_cast(D); + return Dependence(D).type(); } inline TypeDependence toTypeDependence(TemplateArgumentDependence D) { - // Supported bits all have the same representation. - return static_cast(D); + return Dependence(D).type(); } inline NestedNameSpecifierDependence toNestedNameSpecifierDependendence(TypeDependence D) { - // This works because both classes share the same bit representation. - return static_cast( - D & ~TypeDependence::VariablyModified); + return Dependence(D).nestedNameSpecifier(); } inline TemplateArgumentDependence toTemplateArgumentDependence(TypeDependence D) { - // This works because both classes share the same bit representation. - return static_cast( - D & ~TypeDependence::VariablyModified); + return Dependence(D).templateArgument(); } inline TemplateArgumentDependence toTemplateArgumentDependence(TemplateNameDependence D) { - // This works because both classes share the same bit representation. - return static_cast(D); + return Dependence(D).templateArgument(); } inline TemplateArgumentDependence -toTemplateArgumentDependence(ExprDependence ED) { - TemplateArgumentDependence TAD = TemplateArgumentDependence::None; - if (ED & (ExprDependence::Type | ExprDependence::Value)) - TAD |= TemplateArgumentDependence::Dependent; - if (ED & ExprDependence::Instantiation) - TAD |= TemplateArgumentDependence::Instantiation; - if (ED & ExprDependence::UnexpandedPack) - TAD |= TemplateArgumentDependence::UnexpandedPack; - return TAD; +toTemplateArgumentDependence(ExprDependence D) { + return Dependence(D).templateArgument(); } inline TemplateNameDependence toTemplateNameDependence(NestedNameSpecifierDependence D) { - return static_cast(D); + return Dependence(D).templateName(); } LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index fa49182728194..e566e3c6ab899 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2026,7 +2026,8 @@ class PredefinedExpr final static StringRef getIdentKindName(IdentKind IK); static std::string ComputeName(IdentKind IK, const Decl *CurrentDecl); - static std::string ComputeName(ASTContext &Ctx, IdentKind IK, const QualType Ty); + static std::string ComputeName(ASTContext &Context, IdentKind IK, + const QualType Ty); SourceLocation getBeginLoc() const { return getLocation(); } SourceLocation getEndLoc() const { return getLocation(); } diff --git a/clang/include/clang/AST/ExprOpenMP.h b/clang/include/clang/AST/ExprOpenMP.h index f971ed8457bcd..dc6e061604b31 100644 --- a/clang/include/clang/AST/ExprOpenMP.h +++ b/clang/include/clang/AST/ExprOpenMP.h @@ -116,6 +116,258 @@ class OMPArraySectionExpr : public Expr { return const_child_range(&SubExprs[BASE], &SubExprs[END_EXPR]); } }; + +/// An explicit cast in C or a C-style cast in C++, which uses the syntax +/// ([s1][s2]...[sn])expr. For example: @c ([3][3])f. +class OMPArrayShapingExpr final + : public Expr, + private llvm::TrailingObjects { + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; + /// Base node. + SourceLocation LPLoc; /// The location of the left paren + SourceLocation RPLoc; /// The location of the right paren + unsigned NumDims = 0; /// Number of dimensions in the shaping expression. + + /// Construct full expression. + OMPArrayShapingExpr(QualType ExprTy, Expr *Op, SourceLocation L, + SourceLocation R, ArrayRef Dims); + + /// Construct an empty expression. + explicit OMPArrayShapingExpr(EmptyShell Shell, unsigned NumDims) + : Expr(OMPArrayShapingExprClass, Shell), NumDims(NumDims) {} + + /// Sets the dimensions for the array shaping. + void setDimensions(ArrayRef Dims); + + /// Sets the base expression for array shaping operation. + void setBase(Expr *Op) { getTrailingObjects()[NumDims] = Op; } + + /// Sets source ranges for the brackets in the array shaping operation. + void setBracketsRanges(ArrayRef BR); + + unsigned numTrailingObjects(OverloadToken) const { + // Add an extra one for the base expression. + return NumDims + 1; + } + + unsigned numTrailingObjects(OverloadToken) const { + return NumDims; + } + +public: + static OMPArrayShapingExpr *Create(const ASTContext &Context, QualType T, + Expr *Op, SourceLocation L, + SourceLocation R, ArrayRef Dims, + ArrayRef BracketRanges); + + static OMPArrayShapingExpr *CreateEmpty(const ASTContext &Context, + unsigned NumDims); + + SourceLocation getLParenLoc() const { return LPLoc; } + void setLParenLoc(SourceLocation L) { LPLoc = L; } + + SourceLocation getRParenLoc() const { return RPLoc; } + void setRParenLoc(SourceLocation L) { RPLoc = L; } + + SourceLocation getBeginLoc() const LLVM_READONLY { return LPLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { + return getBase()->getEndLoc(); + } + + /// Fetches the dimensions for array shaping expression. + ArrayRef getDimensions() const { + return llvm::makeArrayRef(getTrailingObjects(), NumDims); + } + + /// Fetches source ranges for the brackets os the array shaping expression. + ArrayRef getBracketsRanges() const { + return llvm::makeArrayRef(getTrailingObjects(), NumDims); + } + + /// Fetches base expression of array shaping expression. + Expr *getBase() { return getTrailingObjects()[NumDims]; } + const Expr *getBase() const { return getTrailingObjects()[NumDims]; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPArrayShapingExprClass; + } + + // Iterators + child_range children() { + Stmt **Begin = reinterpret_cast(getTrailingObjects()); + return child_range(Begin, Begin + NumDims + 1); + } + const_child_range children() const { + Stmt *const *Begin = + reinterpret_cast(getTrailingObjects()); + return const_child_range(Begin, Begin + NumDims + 1); + } +}; + +/// OpenMP 5.0 [2.1.6 Iterators] +/// Iterators are identifiers that expand to multiple values in the clause on +/// which they appear. +/// The syntax of the iterator modifier is as follows: +/// \code +/// iterator(iterators-definition) +/// \endcode +/// where iterators-definition is one of the following: +/// \code +/// iterator-specifier [, iterators-definition ] +/// \endcode +/// where iterator-specifier is one of the following: +/// \code +/// [ iterator-type ] identifier = range-specification +/// \endcode +/// where identifier is a base language identifier. +/// iterator-type is a type name. +/// range-specification is of the form begin:end[:step], where begin and end are +/// expressions for which their types can be converted to iterator-type and step +/// is an integral expression. +/// In an iterator-specifier, if the iterator-type is not specified then the +/// type of that iterator is of int type. +/// The iterator-type must be an integral or pointer type. +/// The iterator-type must not be const qualified. +class OMPIteratorExpr final + : public Expr, + private llvm::TrailingObjects { +public: + /// Iterator range representation begin:end[:step]. + struct IteratorRange { + Expr *Begin = nullptr; + Expr *End = nullptr; + Expr *Step = nullptr; + }; + /// Iterator definition representation. + struct IteratorDefinition { + Decl *IteratorDecl = nullptr; + IteratorRange Range; + SourceLocation AssignmentLoc; + SourceLocation ColonLoc, SecondColonLoc; + }; + +private: + friend TrailingObjects; + friend class ASTStmtReader; + friend class ASTStmtWriter; + + /// Offset in the list of expressions for subelements of the ranges. + enum class RangeExprOffset { + Begin = 0, + End = 1, + Step = 2, + Total = 3, + }; + /// Offset in the list of locations for subelements of colon symbols + /// locations. + enum class RangeLocOffset { + AssignLoc = 0, + FirstColonLoc = 1, + SecondColonLoc = 2, + Total = 3, + }; + /// Location of 'iterator' keyword. + SourceLocation IteratorKwLoc; + /// Location of '('. + SourceLocation LPLoc; + /// Location of ')'. + SourceLocation RPLoc; + /// Number of iterator definitions. + unsigned NumIterators = 0; + + OMPIteratorExpr(QualType ExprTy, SourceLocation IteratorKwLoc, + SourceLocation L, SourceLocation R, + ArrayRef Data); + + /// Construct an empty expression. + explicit OMPIteratorExpr(EmptyShell Shell, unsigned NumIterators) + : Expr(OMPIteratorExprClass, Shell), NumIterators(NumIterators) {} + + /// Sets basic declaration for the specified iterator definition. + void setIteratorDeclaration(unsigned I, Decl *D); + + /// Sets the location of the assignment symbol for the specified iterator + /// definition. + void setAssignmentLoc(unsigned I, SourceLocation Loc); + + /// Sets begin, end and optional step expressions for specified iterator + /// definition. + void setIteratorRange(unsigned I, Expr *Begin, SourceLocation ColonLoc, + Expr *End, SourceLocation SecondColonLoc, Expr *Step); + + unsigned numTrailingObjects(OverloadToken) const { + return NumIterators; + } + + unsigned numTrailingObjects(OverloadToken) const { + return NumIterators * static_cast(RangeExprOffset::Total); + } + +public: + static OMPIteratorExpr *Create(const ASTContext &Context, QualType T, + SourceLocation IteratorKwLoc, SourceLocation L, + SourceLocation R, + ArrayRef Data); + + static OMPIteratorExpr *CreateEmpty(const ASTContext &Context, + unsigned NumIterators); + + SourceLocation getLParenLoc() const { return LPLoc; } + void setLParenLoc(SourceLocation L) { LPLoc = L; } + + SourceLocation getRParenLoc() const { return RPLoc; } + void setRParenLoc(SourceLocation L) { RPLoc = L; } + + SourceLocation getIteratorKwLoc() const { return IteratorKwLoc; } + void setIteratorKwLoc(SourceLocation L) { IteratorKwLoc = L; } + SourceLocation getBeginLoc() const LLVM_READONLY { return IteratorKwLoc; } + SourceLocation getEndLoc() const LLVM_READONLY { return RPLoc; } + + /// Gets the iterator declaration for the given iterator. + Decl *getIteratorDecl(unsigned I); + const Decl *getIteratorDecl(unsigned I) const { + return const_cast(this)->getIteratorDecl(I); + } + + /// Gets the iterator range for the given iterator. + IteratorRange getIteratorRange(unsigned I); + const IteratorRange getIteratorRange(unsigned I) const { + return const_cast(this)->getIteratorRange(I); + } + + /// Gets the location of '=' for the given iterator definition. + SourceLocation getAssignLoc(unsigned I) const; + /// Gets the location of the first ':' in the range for the given iterator + /// definition. + SourceLocation getColonLoc(unsigned I) const; + /// Gets the location of the second ':' (if any) in the range for the given + /// iteratori definition. + SourceLocation getSecondColonLoc(unsigned I) const; + + /// Returns number of iterator definitions. + unsigned numOfIterators() const { return NumIterators; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPIteratorExprClass; + } + + // Iterators + child_range children() { + Stmt **Begin = reinterpret_cast(getTrailingObjects()); + return child_range( + Begin, Begin + NumIterators * static_cast(RangeExprOffset::Total)); + } + const_child_range children() const { + Stmt *const *Begin = + reinterpret_cast(getTrailingObjects()); + return const_child_range( + Begin, Begin + NumIterators * static_cast(RangeExprOffset::Total)); + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 29c251ef7ee69..efa6d0554a7ca 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -4372,6 +4372,9 @@ class OMPDependClause final /// Set colon location. void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + /// Sets optional dependency modifier. + void setModifier(Expr *DepModifier); + public: /// Creates clause with a list of variables \a VL. /// @@ -4387,7 +4390,7 @@ class OMPDependClause final /// clause. static OMPDependClause *Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, + SourceLocation EndLoc, Expr *DepModifier, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VL, unsigned NumLoops); @@ -4404,6 +4407,12 @@ class OMPDependClause final /// Get dependency type. OpenMPDependClauseKind getDependencyKind() const { return DepKind; } + /// Return optional depend modifier. + Expr *getModifier(); + const Expr *getModifier() const { + return const_cast(this)->getModifier(); + } + /// Get dependency type location. SourceLocation getDependencyLoc() const { return DepLoc; } @@ -5240,19 +5249,14 @@ class OMPMapClause final : public OMPMappableExprListClause, return getUniqueDeclarationsNum() + getTotalComponentListNum(); } -public: - /// Number of allowed map-type-modifiers. - static constexpr unsigned NumberOfModifiers = - OMPC_MAP_MODIFIER_last - OMPC_MAP_MODIFIER_unknown - 1; - private: /// Map-type-modifiers for the 'map' clause. - OpenMPMapModifierKind MapTypeModifiers[NumberOfModifiers] = { + OpenMPMapModifierKind MapTypeModifiers[NumberOfOMPMapClauseModifiers] = { OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown}; /// Location of map-type-modifiers for the 'map' clause. - SourceLocation MapTypeModifiersLoc[NumberOfModifiers]; + SourceLocation MapTypeModifiersLoc[NumberOfOMPMapClauseModifiers]; /// Map type for the 'map' clause. OpenMPMapClauseKind MapType = OMPC_MAP_unknown; @@ -5321,7 +5325,7 @@ class OMPMapClause final : public OMPMappableExprListClause, /// \param I index for map-type-modifier. /// \param T map-type-modifier for the clause. void setMapTypeModifier(unsigned I, OpenMPMapModifierKind T) { - assert(I < NumberOfModifiers && + assert(I < NumberOfOMPMapClauseModifiers && "Unexpected index to store map type modifier, exceeds array size."); MapTypeModifiers[I] = T; } @@ -5331,7 +5335,7 @@ class OMPMapClause final : public OMPMappableExprListClause, /// \param I index for map-type-modifier location. /// \param TLoc map-type-modifier location. void setMapTypeModifierLoc(unsigned I, SourceLocation TLoc) { - assert(I < NumberOfModifiers && + assert(I < NumberOfOMPMapClauseModifiers && "Index to store map type modifier location exceeds array size."); MapTypeModifiersLoc[I] = TLoc; } @@ -5406,7 +5410,7 @@ class OMPMapClause final : public OMPMappableExprListClause, /// /// \param Cnt index for map-type-modifier. OpenMPMapModifierKind getMapTypeModifier(unsigned Cnt) const LLVM_READONLY { - assert(Cnt < NumberOfModifiers && + assert(Cnt < NumberOfOMPMapClauseModifiers && "Requested modifier exceeds the total number of modifiers."); return MapTypeModifiers[Cnt]; } @@ -5416,7 +5420,7 @@ class OMPMapClause final : public OMPMappableExprListClause, /// /// \param Cnt index for map-type-modifier location. SourceLocation getMapTypeModifierLoc(unsigned Cnt) const LLVM_READONLY { - assert(Cnt < NumberOfModifiers && + assert(Cnt < NumberOfOMPMapClauseModifiers && "Requested modifier location exceeds total number of modifiers."); return MapTypeModifiersLoc[Cnt]; } @@ -7135,6 +7139,19 @@ class OMPClausePrinter final : public OMPClauseVisitor { #include "clang/Basic/OpenMPKinds.def" }; +struct OMPTraitProperty { + llvm::omp::TraitProperty Kind = llvm::omp::TraitProperty::invalid; +}; +struct OMPTraitSelector { + Expr *ScoreOrCondition = nullptr; + llvm::omp::TraitSelector Kind = llvm::omp::TraitSelector::invalid; + llvm::SmallVector Properties; +}; +struct OMPTraitSet { + llvm::omp::TraitSet Kind = llvm::omp::TraitSet::invalid; + llvm::SmallVector Selectors; +}; + /// Helper data structure representing the traits in a match clause of an /// `declare variant` or `metadirective`. The outer level is an ordered /// collection of selector sets, each with an associated kind and an ordered @@ -7146,27 +7163,17 @@ class OMPTraitInfo { friend class ASTContext; public: - struct OMPTraitProperty { - llvm::omp::TraitProperty Kind = llvm::omp::TraitProperty::invalid; - }; - struct OMPTraitSelector { - Expr *ScoreOrCondition = nullptr; - llvm::omp::TraitSelector Kind = llvm::omp::TraitSelector::invalid; - llvm::SmallVector Properties; - }; - struct OMPTraitSet { - llvm::omp::TraitSet Kind = llvm::omp::TraitSet::invalid; - llvm::SmallVector Selectors; - }; + /// Reconstruct a (partial) OMPTraitInfo object from a mangled name. + OMPTraitInfo(StringRef MangledName); /// The outermost level of selector sets. llvm::SmallVector Sets; bool anyScoreOrCondition( llvm::function_ref Cond) { - return llvm::any_of(Sets, [&](OMPTraitInfo::OMPTraitSet &Set) { + return llvm::any_of(Sets, [&](OMPTraitSet &Set) { return llvm::any_of( - Set.Selectors, [&](OMPTraitInfo::OMPTraitSelector &Selector) { + Set.Selectors, [&](OMPTraitSelector &Selector) { return Cond(Selector.ScoreOrCondition, /* IsScore */ Selector.Kind != llvm::omp::TraitSelector::user_condition); @@ -7178,9 +7185,14 @@ class OMPTraitInfo { /// former is a flat representation the actual main difference is that the /// latter uses clang::Expr to store the score/condition while the former is /// independent of clang. Thus, expressions and conditions are evaluated in - /// this method. + /// this method. If \p DeviceSetOnly is true, only the device selector set, if + /// present, is put in \p VMI, otherwise all selector sets are put in \p VMI. void getAsVariantMatchInfo(ASTContext &ASTCtx, - llvm::omp::VariantMatchInfo &VMI) const; + llvm::omp::VariantMatchInfo &VMI, + bool DeviceSetOnly) const; + + /// Return a string representation identifying this context selector. + std::string getMangledName() const; /// Print a human readable representation into \p OS. void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index dedfccda265da..d00deab95d9fd 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -57,7 +57,8 @@ struct PrintingPolicy { SuppressLifetimeQualifiers(false), SuppressTypedefs(false), SuppressTemplateArgsInCXXConstructors(false), Bool(LO.Bool), Restrict(LO.C99), Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11), - UseVoidForZeroParams(!LO.CPlusPlus), TerseOutput(false), + UseVoidForZeroParams(!LO.CPlusPlus), + SplitTemplateClosers(!LO.CPlusPlus11), TerseOutput(false), PolishForDeclaration(false), Half(LO.Half), MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), @@ -206,6 +207,10 @@ struct PrintingPolicy { /// with zero parameters. unsigned UseVoidForZeroParams : 1; + /// Whether nested templates must be closed like 'a >' rather than + /// 'a>'. + unsigned SplitTemplateClosers : 1; + /// Provide a 'terse' output. /// /// For example, in this mode we don't print function bodies, class members, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 2f598564f3077..3453338496599 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2551,6 +2551,8 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {}) DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) +DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {}) +DEF_TRAVERSE_STMT(OMPIteratorExpr, {}) DEF_TRAVERSE_STMT(BlockExpr, { TRY_TO(TraverseDecl(S->getBlockDecl())); diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 87e1d7f26a168..8c7f0ecad3ef6 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -21,6 +21,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" @@ -310,9 +311,9 @@ class alignas(void *) Stmt { unsigned ValueKind : 2; unsigned ObjectKind : 3; - unsigned /*ExprDependence*/ Dependent : ExprDependenceBits; + unsigned /*ExprDependence*/ Dependent : llvm::BitWidth; }; - enum { NumExprBits = NumStmtBits + 5 + ExprDependenceBits }; + enum { NumExprBits = NumStmtBits + 5 + llvm::BitWidth }; class ConstantExprBitfields { friend class ASTStmtReader; diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index b08d1e482be8b..0fb4baf0ca4d5 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -274,6 +274,7 @@ class TextNodeDumper void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node); void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node); void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node); + void VisitOMPIteratorExpr(const OMPIteratorExpr *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 85a7d682f5c8c..283ed4b2a6243 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1475,7 +1475,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { unsigned TC : 8; /// Store information on the type dependency. - /*TypeDependence*/ unsigned Dependence : TypeDependenceBits; + unsigned Dependence : llvm::BitWidth; /// True if the cache (i.e. the bitfields here starting with /// 'Cache') is valid. @@ -1504,7 +1504,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { return CachedLocalOrUnnamed; } }; - enum { NumTypeBits = 8 + TypeDependenceBits + 6 }; + enum { NumTypeBits = 8 + llvm::BitWidth + 6 }; protected: // These classes allow subclasses to somewhat cleanly pack bitfields @@ -1658,11 +1658,8 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { /// The kind of vector, either a generic vector type or some /// target-specific vector type such as for AltiVec or Neon. unsigned VecKind : 3; - /// The number of elements in the vector. - unsigned NumElements : 29 - NumTypeBits; - - enum { MaxNumElements = (1 << (29 - NumTypeBits)) - 1 }; + uint32_t NumElements; }; class AttributedTypeBitfields { @@ -2119,6 +2116,11 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { /// than implicitly __strong. bool isObjCARCImplicitlyUnretainedType() const; + /// Check if the type is the CUDA device builtin surface type. + bool isCUDADeviceBuiltinSurfaceType() const; + /// Check if the type is the CUDA device builtin texture type. + bool isCUDADeviceBuiltinTextureType() const; + /// Return the implicit lifetime for this type, which must not be dependent. Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; @@ -2142,6 +2144,11 @@ class alignas(8) Type : public ExtQualsTypeCommonBase { return static_cast(TypeBits.Dependence); } + /// Whether this type is an error type. + bool containsErrors() const { + return getDependence() & TypeDependence::Error; + } + /// Whether this type is a dependent type, meaning that its definition /// somehow depends on a template parameter (C++ [temp.dep.type]). bool isDependentType() const { @@ -3247,10 +3254,6 @@ class VectorType : public Type, public llvm::FoldingSetNode { QualType getElementType() const { return ElementType; } unsigned getNumElements() const { return VectorTypeBits.NumElements; } - static bool isVectorSizeTooLarge(unsigned NumElements) { - return NumElements > VectorTypeBitfields::MaxNumElements; - } - bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -6682,9 +6685,9 @@ inline bool Type::isTemplateTypeParmType() const { } inline bool Type::isSpecificBuiltinType(unsigned K) const { - if (const BuiltinType *BT = getAs()) - if (BT->getKind() == (BuiltinType::Kind) K) - return true; + if (const BuiltinType *BT = getAs()) { + return BT->getKind() == static_cast(K); + } return false; } @@ -6703,9 +6706,7 @@ inline const BuiltinType *Type::getAsPlaceholderType() const { inline bool Type::isSpecificPlaceholderType(unsigned K) const { assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); - if (const auto *BT = dyn_cast(this)) - return (BT->getKind() == (BuiltinType::Kind) K); - return false; + return isSpecificBuiltinType(K); } inline bool Type::isNonOverloadPlaceholderType() const { @@ -6715,34 +6716,24 @@ inline bool Type::isNonOverloadPlaceholderType() const { } inline bool Type::isVoidType() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Void; - return false; + return isSpecificBuiltinType(BuiltinType::Void); } inline bool Type::isHalfType() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Half; // FIXME: Should we allow complex __fp16? Probably not. - return false; + return isSpecificBuiltinType(BuiltinType::Half); } inline bool Type::isFloat16Type() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Float16; - return false; + return isSpecificBuiltinType(BuiltinType::Float16); } inline bool Type::isFloat128Type() const { - if (const auto *BT = dyn_cast(CanonicalType)) - return BT->getKind() == BuiltinType::Float128; - return false; + return isSpecificBuiltinType(BuiltinType::Float128); } inline bool Type::isNullPtrType() const { - if (const auto *BT = getAs()) - return BT->getKind() == BuiltinType::NullPtr; - return false; + return isSpecificBuiltinType(BuiltinType::NullPtr); } bool IsEnumDeclComplete(EnumDecl *); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index dd873ab2595c9..6f7a4b7949b08 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1073,16 +1073,20 @@ def CUDADeviceBuiltin : IgnoredAttr { let LangOpts = [CUDA]; } -def CUDADeviceBuiltinSurfaceType : IgnoredAttr { +def CUDADeviceBuiltinSurfaceType : InheritableAttr { let Spellings = [GNU<"device_builtin_surface_type">, Declspec<"__device_builtin_surface_type__">]; let LangOpts = [CUDA]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [CUDADeviceBuiltinSurfaceTypeDocs]; } -def CUDADeviceBuiltinTextureType : IgnoredAttr { +def CUDADeviceBuiltinTextureType : InheritableAttr { let Spellings = [GNU<"device_builtin_texture_type">, Declspec<"__device_builtin_texture_type__">]; let LangOpts = [CUDA]; + let Subjects = SubjectList<[CXXRecord]>; + let Documentation = [CUDADeviceBuiltinTextureTypeDocs]; } def CUDAGlobal : InheritableAttr { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index e8cc79967f059..7d375ac502976 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -140,7 +140,8 @@ def NoEscapeDocs : Documentation { the compiler that the pointer cannot escape: that is, no reference to the object the pointer points to that is derived from the parameter value will survive after the function returns. Users are responsible for making sure parameters -annotated with ``noescape`` do not actuallly escape. +annotated with ``noescape`` do not actually escape. Calling ``free()`` on such +a parameter does not constitute an escape. For example: @@ -484,7 +485,7 @@ parameter. Note that this attribute merely informs the compiler that a function always returns a sufficiently aligned pointer. It does not cause the compiler to emit code to enforce that alignment. The behavior is undefined if the returned -poitner is not sufficiently aligned. +pointer is not sufficiently aligned. }]; } @@ -942,11 +943,11 @@ The behavior of a function with respect to reference counting for Foundation convention (e.g. functions starting with "get" are assumed to return at ``+0``). -It can be overriden using a family of the following attributes. In +It can be overridden using a family of the following attributes. In Objective-C, the annotation ``__attribute__((ns_returns_retained))`` applied to a function communicates that the object is returned at ``+1``, and the caller is responsible for freeing it. -Similiarly, the annotation ``__attribute__((ns_returns_not_retained))`` +Similarly, the annotation ``__attribute__((ns_returns_not_retained))`` specifies that the object is returned at ``+0`` and the ownership remains with the callee. The annotation ``__attribute__((ns_consumes_self))`` specifies that @@ -1290,7 +1291,7 @@ correspond to different platforms. For most platforms, the availability attribute with the platform corresponding to the target platform will be used; any others will be ignored. However, the availability for ``watchOS`` and ``tvOS`` can be implicitly inferred from an ``iOS`` availability attribute. -Any explicit availability attributes for those platforms are still prefered over +Any explicit availability attributes for those platforms are still preferred over the implicitly inferred availability attributes. If no availability attribute specifies availability for the current target platform, the availability attributes are ignored. Supported platforms are: @@ -1398,7 +1399,7 @@ pragma rather than using the inferred ``iOS`` availability from the declaration: void getsThePragmaTVOSAvailabilityAttribute(void) __attribute__((availability(iOS,introduced=11.0))); #pragma clang attribute pop -The compiler is also able to apply implicly inferred attributes from a pragma +The compiler is also able to apply implicitly inferred attributes from a pragma as well. For example, when targeting ``tvOS``, the function below will receive a ``tvOS`` availability attribute that is implicitly inferred from the ``iOS`` availability attribute applied by the pragma: @@ -1716,7 +1717,7 @@ def BPFPreserveAccessIndexDocs : Documentation { Clang supports the ``__attribute__((preserve_access_index))`` attribute for the BPF target. This attribute may be attached to a struct or union declaration, where if -g is specified, it enables -preserving struct or union member access debuginfo indicies of this +preserving struct or union member access debuginfo indices of this struct or union, similar to clang ``__builtin_preserve_acceess_index()``. }]; } @@ -1732,7 +1733,7 @@ directly as an interrupt service routine. By default, the compiler will produce a function prologue and epilogue suitable for an interrupt service routine that handles an External Interrupt Controller (eic) -generated interrupt. This behaviour can be explicitly requested with the "eic" +generated interrupt. This behavior can be explicitly requested with the "eic" argument. Otherwise, for use with vectored interrupt mode, the argument passed should be @@ -4118,7 +4119,7 @@ using the Swift calling convention for a function or function pointer. The lowering for the Swift calling convention, as described by the Swift ABI documentation, occurs in multiple phases. The first, "high-level" phase breaks down the formal parameters and results into innately direct -and indirect components, adds implicit paraameters for the generic +and indirect components, adds implicit parameters for the generic signature, and assigns the context and error ABI treatments to parameters where applicable. The second phase breaks down the direct parameters and results from the first phase and assigns them to registers or the @@ -4160,7 +4161,7 @@ of the first phase, as follows: ``swiftcall`` does not support variadic arguments or unprototyped functions. The parameter ABI treatment attributes are aspects of the function type. -A function type which which applies an ABI treatment attribute to a +A function type which applies an ABI treatment attribute to a parameter is a different type from an otherwise-identical function type that does not. A single parameter may not have multiple ABI treatment attributes. @@ -4289,7 +4290,7 @@ with different ABI versions supported. For example, a newer version of a class could have a different set of data members and thus have a different size. Using the ``abi_tag`` attribute, it is possible to have different mangled names for a global variable of the class type. Therefore, the old code could keep using -the old manged name and the new code will use the new mangled name with tags. +the old mangled name and the new code will use the new mangled name with tags. }]; } @@ -4443,9 +4444,9 @@ takes precedence over the command line option ``-fpatchable-function-entry=N,M`` def TransparentUnionDocs : Documentation { let Category = DocCatDecl; let Content = [{ -This attribute can be applied to a union to change the behaviour of calls to +This attribute can be applied to a union to change the behavior of calls to functions that have an argument with a transparent union type. The compiler -behaviour is changed in the following manner: +behavior is changed in the following manner: - A value whose type is any member of the transparent union can be passed as an argument without the need to cast that value. @@ -4977,7 +4978,7 @@ When applied to the definition of a function, method, or block, every parameter of the function with implicit strong retainable object pointer type is considered externally-retained, and becomes ``const``. By explicitly annotating a parameter with ``__strong``, you can opt back into the default -non-externally-retained behaviour for that parameter. For instance, +non-externally-retained behavior for that parameter. For instance, ``first_param`` is externally-retained below, but not ``second_param``: .. code-block:: objc @@ -4999,7 +5000,7 @@ def MIGConventionDocs : Documentation { The Mach Interface Generator release-on-success convention dictates functions that follow it to only release arguments passed to them when they return "success" (a ``kern_return_t`` error code that indicates that -no errors have occured). Otherwise the release is performed by the MIG client +no errors have occurred). Otherwise the release is performed by the MIG client that called the function. The annotation ``__attribute__((mig_server_routine))`` is applied in order to specify which functions are expected to follow the convention. This allows the Static Analyzer to find bugs caused by violations of @@ -5063,6 +5064,28 @@ the initializer on host side. }]; } +def CUDADeviceBuiltinSurfaceTypeDocs : Documentation { + let Category = DocCatType; + let Content = [{ +The ``device_builtin_surface_type`` attribute can be applied to a class +template when declaring the surface reference. A surface reference variable +could be accessed on the host side and, on the device side, might be translated +into an internal surface object, which is established through surface bind and +unbind runtime APIs. + }]; +} + +def CUDADeviceBuiltinTextureTypeDocs : Documentation { + let Category = DocCatType; + let Content = [{ +The ``device_builtin_texture_type`` attribute can be applied to a class +template when declaring the texture reference. A texture reference variable +could be accessed on the host side and, on the device side, might be translated +into an internal texture object, which is established through texture bind and +unbind runtime APIs. + }]; +} + def LifetimeOwnerDocs : Documentation { let Category = DocCatDecl; let Content = [{ diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 0aa11fa6ac177..0b411d9bd8e45 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -472,7 +472,7 @@ BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") BUILTIN(__builtin_va_start, "vA.", "nt") BUILTIN(__builtin_va_end, "vA", "n") BUILTIN(__builtin_va_copy, "vAA", "n") -BUILTIN(__builtin_stdarg_start, "vA.", "n") +BUILTIN(__builtin_stdarg_start, "vA.", "nt") BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nc") BUILTIN(__builtin_bcmp, "ivC*vC*z", "Fn") BUILTIN(__builtin_bcopy, "vv*v*z", "n") diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index a9143ad8292c3..b42c8a77c4bc3 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -33,6 +33,10 @@ BUILTIN(__builtin_amdgcn_workitem_id_x, "Ui", "nc") BUILTIN(__builtin_amdgcn_workitem_id_y, "Ui", "nc") BUILTIN(__builtin_amdgcn_workitem_id_z, "Ui", "nc") +BUILTIN(__builtin_amdgcn_workgroup_size_x, "Us", "nc") +BUILTIN(__builtin_amdgcn_workgroup_size_y, "Us", "nc") +BUILTIN(__builtin_amdgcn_workgroup_size_z, "Us", "nc") + BUILTIN(__builtin_amdgcn_mbcnt_hi, "UiUiUi", "nc") BUILTIN(__builtin_amdgcn_mbcnt_lo, "UiUiUi", "nc") diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def index d6aa46de02f95..ccb6f341d63da 100644 --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -1900,6 +1900,9 @@ TARGET_BUILTIN(__builtin_ia32_invpcid, "vUiv*", "nc", "invpcid") TARGET_BUILTIN(__builtin_ia32_enqcmd, "Ucv*vC*", "n", "enqcmd") TARGET_BUILTIN(__builtin_ia32_enqcmds, "Ucv*vC*", "n", "enqcmd") +// SERIALIZE +TARGET_BUILTIN(__builtin_ia32_serialize, "v", "n", "serialize") + // MSVC TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 5b59954fae7bb..0faa013ac4975 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -254,6 +254,7 @@ CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables. CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer. CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer. CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate. +CODEGENOPT(CallGraphProfile , 1, 0) ///< Run call graph profile. /// Attempt to use register sized accesses to bit-fields in structures, when /// possible. @@ -386,10 +387,6 @@ CODEGENOPT(ForceEmitVTables, 1, 0) /// Whether to emit an address-significance table into the object file. CODEGENOPT(Addrsig, 1, 0) -ENUM_CODEGENOPT(SignReturnAddress, SignReturnAddressScope, 2, SignReturnAddressScope::None) -ENUM_CODEGENOPT(SignReturnAddressKey, SignReturnAddressKeyValue, 1, SignReturnAddressKeyValue::AKey) -CODEGENOPT(BranchTargetEnforcement, 1, 0) - /// Whether to emit unused static constants. CODEGENOPT(KeepStaticConsts, 1, 0) @@ -399,4 +396,3 @@ CODEGENOPT(ForceAAPCSBitfieldLoad, 1, 0) #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT - diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index d435bebcdcf97..60d418688710e 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -110,14 +110,6 @@ class CodeGenOptions : public CodeGenOptionsBase { Embed_Marker // Embed a marker as a placeholder for bitcode. }; - enum class SignReturnAddressScope { - None, // No signing for any function - NonLeaf, // Sign the return address of functions that spill LR - All // Sign the return address of all functions - }; - - enum class SignReturnAddressKeyValue { AKey, BKey }; - enum class FramePointerKind { None, // Omit all frame pointers. NonLeaf, // Keep non-leaf frame pointers. diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index da572957d10dd..c2ebf87343047 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -117,6 +117,7 @@ enum class CudaFeature { CUDA_USES_FATBIN_REGISTER_END, }; +CudaVersion ToCudaVersion(llvm::VersionTuple); bool CudaFeatureEnabled(llvm::VersionTuple, CudaFeature); bool CudaFeatureEnabled(CudaVersion, CudaFeature); diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 0b3a1a2575b64..8cbce0572818c 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -366,6 +366,8 @@ def err_analyzer_checker_option_unknown : Error< "checker '%0' has no option called '%1'">; def err_analyzer_checker_option_invalid_input : Error< "invalid input for checker option '%0', that expects %1">; +def err_analyzer_checker_incompatible_analyzer_option : Error< + "checker cannot be enabled with analyzer option '%0' == %1">; def err_drv_invalid_hvx_length : Error< "-mhvx-length is not supported without a -mhvx/-mhvx= flag">; @@ -472,13 +474,13 @@ def note_drv_verify_prefix_spelling : Note< "-verify prefixes must start with a letter and contain only alphanumeric" " characters, hyphens, and underscores">; -def warn_drv_experimental_isel_incomplete : Warning< - "-fexperimental-isel support for the '%0' architecture is incomplete">, - InGroup; +def warn_drv_global_isel_incomplete : Warning< + "-fglobal-isel support for the '%0' architecture is incomplete">, + InGroup; -def warn_drv_experimental_isel_incomplete_opt : Warning< - "-fexperimental-isel support is incomplete for this architecture at the current optimization level">, - InGroup; +def warn_drv_global_isel_incomplete_opt : Warning< + "-fglobal-isel support is incomplete for this architecture at the current optimization level">, + InGroup; def warn_drv_moutline_unsupported_opt : Warning< "The '%0' architecture does not support -moutline; flag ignored">, diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 7c7bd7eae3740..84810e657d969 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1160,8 +1160,8 @@ def UnknownArgument : DiagGroup<"unknown-argument">; // compiling OpenCL C/C++ but which is not compatible with the SPIR spec. def SpirCompat : DiagGroup<"spir-compat">; -// Warning for the experimental-isel options. -def ExperimentalISel : DiagGroup<"experimental-isel">; +// Warning for the GlobalISel options. +def GlobalISel : DiagGroup<"global-isel">; // A warning group specifically for warnings related to function // multiversioning. diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 469af4167f8aa..d5e480d557ba9 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1220,6 +1220,10 @@ def err_omp_expected_identifier_for_critical : Error< "expected identifier specifying the name of the 'omp critical' directive">; def err_omp_expected_reduction_identifier : Error< "expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'">; +def err_omp_expected_equal_in_iterator : Error< + "expected '=' in iterator specifier">; +def err_omp_expected_punc_after_iterator : Error< + "expected ',' or ')' after iterator specifier">; def err_omp_decl_in_declare_simd_variant : Error< "function declaration is expected after 'declare %select{simd|variant}0' directive">; def err_omp_unknown_map_type : Error< @@ -1232,8 +1236,11 @@ def err_omp_map_type_modifier_missing : Error< "missing map type modifier">; def err_omp_declare_simd_inbranch_notinbranch : Error< "unexpected '%0' clause, '%1' is specified already">; -def err_expected_end_declare_target : Error< - "expected '#pragma omp end declare target'">; +def err_expected_end_declare_target_or_variant : Error< + "expected '#pragma omp end declare %select{target|variant}0'">; +def err_expected_begin_declare_variant + : Error<"'#pragma omp end declare variant' with no matching '#pragma omp " + "begin declare variant'">; def err_omp_declare_target_unexpected_clause: Error< "unexpected '%0' clause, only %select{'to' or 'link'|'to', 'link' or 'device_type'}1 clauses expected">; def err_omp_expected_clause: Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index b13492fb85152..5d8daa27b5bff 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4957,9 +4957,13 @@ def note_using_value_decl_missing_typename : Note< "add 'typename' to treat this using declaration as a type">; def err_template_kw_refers_to_non_template : Error< - "%0 following the 'template' keyword does not refer to a template">; + "%0%select{| following the 'template' keyword}1 " + "does not refer to a template">; def note_template_kw_refers_to_non_template : Note< "declared as a non-template here">; +def err_template_kw_refers_to_dependent_non_template : Error< + "%0%select{| following the 'template' keyword}1 " + "cannot refer to a dependent template">; def err_template_kw_refers_to_class_template : Error< "'%0%1' instantiated to a class template, not a function template">; def note_referenced_class_template : Note< @@ -5983,7 +5987,7 @@ def err_func_def_incomplete_result : Error< def err_atomic_specifier_bad_type : Error< "_Atomic cannot be applied to " "%select{incomplete |array |function |reference |atomic |qualified |sizeless |}0type " - "%1 %select{||||||which is not trivially copyable}0">; + "%1 %select{|||||||which is not trivially copyable}0">; // Expressions. def select_unary_expr_or_type_trait_kind : TextSubstitution< @@ -8008,6 +8012,22 @@ def err_cuda_ovl_target : Error< def note_cuda_ovl_candidate_target_mismatch : Note< "candidate template ignored: target attributes do not match">; +def err_cuda_device_builtin_surftex_cls_template : Error< + "illegal device builtin %select{surface|texture}0 reference " + "class template %1 declared here">; +def note_cuda_device_builtin_surftex_cls_should_have_n_args : Note< + "%0 needs to have exactly %1 template parameters">; +def note_cuda_device_builtin_surftex_cls_should_have_match_arg : Note< + "the %select{1st|2nd|3rd}1 template parameter of %0 needs to be " + "%select{a type|an integer or enum value}2">; + +def err_cuda_device_builtin_surftex_ref_decl : Error< + "illegal device builtin %select{surface|texture}0 reference " + "type %1 declared here">; +def note_cuda_device_builtin_surftex_should_be_template_class : Note< + "%0 needs to be instantiated from a class template with proper " + "template arguments">; + def warn_non_pod_vararg_with_format_string : Warning< "cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic " "%select{function|block|method|constructor}2; expected type from format " @@ -9706,7 +9726,7 @@ def err_omp_expected_var_name_member_expr : Error< def err_omp_expected_var_name_member_expr_or_array_item : Error< "expected variable name%select{|, data member of current class}0, array element or array section">; def err_omp_expected_addressable_lvalue_or_array_item : Error< - "expected addressable lvalue expression, array element or array section%select{| of non 'omp_depend_t' type}0">; + "expected addressable lvalue expression, array element%select{ or array section|, array section or array shaping expression}0%select{| of non 'omp_depend_t' type}1">; def err_omp_expected_named_var_member_or_array_expression: Error< "expected expression containing only member accesses and/or array sections based on named variables">; def err_omp_bit_fields_forbidden_in_clause : Error< @@ -9781,6 +9801,12 @@ def note_omp_conversion_here : Note< def err_omp_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; +def err_omp_iterator_not_integral_or_pointer : Error< + "expected integral or pointer type as the iterator-type, not %0">; +def err_omp_iterator_step_not_integral : Error< + "iterator step expression %0 is not the integral expression">; +def err_omp_iterator_step_constant_zero : Error< + "iterator step expression %0 evaluates to 0">; def err_omp_required_access : Error< "%0 variable must be %1">; def err_omp_const_variable : Error< @@ -9869,8 +9895,6 @@ def err_omp_reduction_in_task : Error< "reduction variables may not be accessed in an explicit task">; def err_omp_reduction_id_not_compatible : Error< "list item of type %0 is not valid for specified reduction operation: unable to provide default initialization value">; -def err_omp_in_reduction_not_task_reduction : Error< - "in_reduction variable must appear in a task_reduction clause">; def err_omp_reduction_identifier_mismatch : Error< "in_reduction variable must have the same reduction operation as in a task_reduction clause">; def note_omp_previous_reduction_identifier : Note< @@ -9881,7 +9905,7 @@ def err_omp_prohibited_region : Error< "; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?|" "; perhaps you forget to enclose 'omp %3' directive into a target region?|" "; perhaps you forget to enclose 'omp %3' directive into a teams region?|" - "; perhaps you forget to enclose 'omp %3' directive into a for, simd, or for simd region?}2">; + "; perhaps you forget to enclose 'omp %3' directive into a for, simd, for simd, parallel for, or parallel for simd region?}2">; def err_omp_prohibited_region_simd : Error< "OpenMP constructs may not be nested inside a simd region%select{| except for ordered simd, simd, scan, or atomic directive}0">; def err_omp_prohibited_region_atomic : Error< @@ -9975,10 +9999,16 @@ def err_omp_declare_mapper_redefinition : Error< def err_omp_invalid_mapper: Error< "cannot find a valid user-defined mapper for type %0 with name %1">; def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">; +def err_omp_array_shaping_use : Error<"OpenMP array shaping operation is not allowed here">; +def err_omp_iterator_use : Error<"OpenMP iterator is not allowed here">; def err_omp_typecheck_section_value : Error< "subscripted value is not an array or pointer">; def err_omp_typecheck_section_not_integer : Error< "array section %select{lower bound|length}0 is not an integer">; +def err_omp_typecheck_shaping_not_integer : Error< + "array shaping operation dimension is not an integer">; +def err_omp_shaping_dimension_not_positive : Error< + "array shaping dimension is evaluated to a non-positive value %0">; def err_omp_section_function_type : Error< "section of pointer to function type %0">; def warn_omp_section_is_char : Warning<"array section %select{lower bound|length}0 is of type 'char'">, @@ -10049,6 +10079,10 @@ def err_omp_depend_sink_source_not_allowed : Error< "'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">; def err_omp_depend_zero_length_array_section_not_allowed : Error< "zero-length array section is not allowed in 'depend' clause">; +def err_omp_depend_sink_source_with_modifier : Error< + "depend modifier cannot be used with 'sink' or 'source' depend type">; +def err_omp_depend_modifier_not_iterator : Error< + "expected iterator specification as depend modifier">; def err_omp_linear_ordered : Error< "'linear' clause cannot be specified along with 'ordered' clause with a parameter">; def err_omp_unexpected_schedule_modifier : Error< @@ -10078,7 +10112,8 @@ def warn_omp_nesting_simd : Warning< InGroup; def err_omp_orphaned_device_directive : Error< "orphaned 'omp %0' directives are prohibited" - "; perhaps you forget to enclose the directive into a %select{|||target |teams|for, simd, or for simd }1region?">; + "; perhaps you forget to enclose the directive into a " + "%select{|||target |teams|for, simd, for simd, parallel for, or parallel for simd }1region?">; def err_omp_reduction_non_addressable_expression : Error< "expected addressable reduction item for the task-based directives">; def err_omp_reduction_with_nogroup : Error< @@ -10118,6 +10153,19 @@ def err_omp_depobj_single_clause_expected : Error< "exactly one of 'depend', 'destroy', or 'update' clauses is expected">; def err_omp_scan_single_clause_expected : Error< "exactly one of 'inclusive' or 'exclusive' clauses is expected">; +def err_omp_inclusive_exclusive_not_reduction : Error< + "the list item must appear in 'reduction' clause with the 'inscan' modifier " + "of the parent directive">; +def err_omp_reduction_not_inclusive_exclusive : Error< + "the inscan reduction list item must appear as a list item in an 'inclusive' or" + " 'exclusive' clause on an inner 'omp scan' directive">; +def err_omp_wrong_inscan_reduction : Error< + "'inscan' modifier can be used only in 'omp for', 'omp simd', 'omp for simd'," + " 'omp parallel for', or 'omp parallel for simd' directive">; +def err_omp_inscan_reduction_expected : Error< + "expected 'reduction' clause with the 'inscan' modifier">; +def note_omp_previous_inscan_reduction : Note< + "'reduction' clause with 'inscan' modifier is used here">; def err_omp_expected_predefined_allocator : Error< "expected one of the predefined allocators for the variables with the static " "storage: 'omp_default_mem_alloc', 'omp_large_cap_mem_alloc', " @@ -10199,10 +10247,16 @@ def err_omp_flush_order_clause_and_list : Error< def note_omp_flush_order_clause_here : Note< "memory order clause '%0' is specified here">; def err_omp_non_lvalue_in_map_or_motion_clauses: Error< - "expected addressable lvalue in '%0' clause" - >; + "expected addressable lvalue in '%0' clause">; def err_omp_event_var_expected : Error< "expected variable of the 'omp_event_handle_t' type%select{|, not %1}0">; +def warn_nested_declare_variant + : Warning<"nesting `omp begin/end declare variant` is not supported yet; " + "nested context ignored">, + InGroup; +def err_omp_non_pointer_type_array_shaping_base : Error< + "expected expression with a pointer to a complete type as a base of an array " + "shaping operation">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index e5ae83331f4c1..f23e7276b0306 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -108,7 +108,10 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { // True if this is the 'import' contextual keyword. unsigned IsModulesImport : 1; - // 29 bits left in a 64-bit word. + // True if this is a mangled OpenMP variant name. + unsigned IsMangledOpenMPVariantName : 1; + + // 28 bits left in a 64-bit word. // Managed by the language front-end. void *FETokenInfo = nullptr; @@ -121,7 +124,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { IsPoisoned(false), IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false), - IsModulesImport(false) {} + IsModulesImport(false), IsMangledOpenMPVariantName(false) {} public: IdentifierInfo(const IdentifierInfo &) = delete; @@ -371,6 +374,12 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { RecomputeNeedsHandleIdentifier(); } + /// Determine whether this is the mangled name of an OpenMP variant. + bool isMangledOpenMPVariantName() const { return IsMangledOpenMPVariantName; } + + /// Set whether this is the mangled name of an OpenMP variant. + void setMangledOpenMPVariantName(bool I) { IsMangledOpenMPVariantName = I; } + /// Return true if this identifier is an editor placeholder. /// /// Editor placeholders are produced by the code-completion engine and are diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 42a9230998f6c..982525d1e4679 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -148,7 +148,7 @@ LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template t LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes") -COMPATIBLE_LANGOPT(RecoveryAST, 1, CPlusPlus, "Preserve expressions in AST when encountering errors") +COMPATIBLE_LANGOPT(RecoveryAST, 1, 0, "Preserve expressions in AST when encountering errors") BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers") LANGOPT(POSIXThreads , 1, 0, "POSIX thread support") @@ -358,6 +358,12 @@ LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors") COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0") +ENUM_LANGOPT(SignReturnAddressScope, SignReturnAddressScopeKind, 2, SignReturnAddressScopeKind::None, + "Scope of return address signing") +ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, SignReturnAddressKeyKind::AKey, + "Key used for return address signing") +LANGOPT(BranchTargetEnforcement, 1, 0, "Branch-target enforcement enabled") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 0c0db4e03fb84..339f448a9632c 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -234,6 +234,22 @@ class LangOptions : public LangOptionsBase { All, }; + enum class SignReturnAddressScopeKind { + /// No signing for any function. + None, + /// Sign the return address of functions that spill LR. + NonLeaf, + /// Sign the return address of all functions, + All + }; + + enum class SignReturnAddressKeyKind { + /// Return address signing uses APIA key. + AKey, + /// Return address signing uses APIB key. + BKey + }; + public: /// Set of enabled sanitizers. SanitizerSet Sanitize; @@ -359,6 +375,21 @@ class LangOptions : public LangOptionsBase { /// Return the OpenCL C or C++ version as a VersionTuple. VersionTuple getOpenCLVersionTuple() const; + + /// Check if return address signing is enabled. + bool hasSignReturnAddress() const { + return getSignReturnAddressScope() != SignReturnAddressScopeKind::None; + } + + /// Check if return address signing uses AKey. + bool isSignReturnAddressWithAKey() const { + return getSignReturnAddressKey() == SignReturnAddressKeyKind::AKey; + } + + /// Check if leaf functions are also signed. + bool isSignReturnAddressScopeAll() const { + return getSignReturnAddressScope() == SignReturnAddressScopeKind::All; + } }; /// Floating point control options diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h index 9c2bc155cd4f6..c47eb4587a574 100644 --- a/clang/include/clang/Basic/Module.h +++ b/clang/include/clang/Basic/Module.h @@ -662,7 +662,7 @@ class ASTSourceDescriptor { StringRef Path; StringRef ASTFile; ASTFileSignature Signature; - const Module *ClangModule = nullptr; + Module *ClangModule = nullptr; public: ASTSourceDescriptor() = default; @@ -670,13 +670,13 @@ class ASTSourceDescriptor { ASTFileSignature Signature) : PCHModuleName(std::move(Name)), Path(std::move(Path)), ASTFile(std::move(ASTFile)), Signature(Signature) {} - ASTSourceDescriptor(const Module &M); + ASTSourceDescriptor(Module &M); std::string getModuleName() const; StringRef getPath() const { return Path; } StringRef getASTFile() const { return ASTFile; } ASTFileSignature getSignature() const { return Signature; } - const Module *getModuleOrNull() const { return ClangModule; } + Module *getModuleOrNull() const { return ClangModule; } }; diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index bfb41ab105ea5..3cf92ead9560e 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -1112,6 +1112,7 @@ OPENMP_DEPOBJ_CLAUSE(update) // Modifiers for 'reduction' clause. OPENMP_REDUCTION_MODIFIER(default) +OPENMP_REDUCTION_MODIFIER(inscan) #undef OPENMP_REDUCTION_MODIFIER #undef OPENMP_SCAN_CLAUSE diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index b567f89b986e0..f12b5545d0c14 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -91,6 +91,10 @@ enum OpenMPMapModifierKind { OMPC_MAP_MODIFIER_last }; + /// Number of allowed map-type-modifiers. +static constexpr unsigned NumberOfOMPMapClauseModifiers = + OMPC_MAP_MODIFIER_last - OMPC_MAP_MODIFIER_unknown - 1; + /// OpenMP modifier kind for 'to' clause. enum OpenMPToModifierKind { #define OPENMP_TO_MODIFIER_KIND(Name) \ diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 478179d4131f4..aecf24f890331 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -70,6 +70,7 @@ def OffsetOfExpr : StmtNode; def UnaryExprOrTypeTraitExpr : StmtNode; def ArraySubscriptExpr : StmtNode; def OMPArraySectionExpr : StmtNode; +def OMPIteratorExpr : StmtNode; def CallExpr : StmtNode; def MemberExpr : StmtNode; def CastExpr : StmtNode; @@ -81,6 +82,7 @@ def BinaryConditionalOperator : StmtNode; def ImplicitCastExpr : StmtNode; def ExplicitCastExpr : StmtNode; def CStyleCastExpr : StmtNode; +def OMPArrayShapingExpr : StmtNode; def CompoundLiteralExpr : StmtNode; def ExtVectorElementExpr : StmtNode; def InitListExpr : StmtNode; diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index cbfcece1b666d..ab47954040719 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -16,7 +16,7 @@ #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/LLVM.h" -#include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/TargetOptions.h" @@ -212,6 +212,8 @@ class TargetInfo : public virtual TransferrableTargetInfo, unsigned ARMCDECoprocMask : 8; + unsigned MaxOpenCLWorkGroupSize; + // TargetInfo Constructor. Default initializes all fields. TargetInfo(const llvm::Triple &T); @@ -273,7 +275,14 @@ class TargetInfo : public virtual TransferrableTargetInfo, // void *__overflow_arg_area; // void *__reg_save_area; // } va_list[1]; - SystemZBuiltinVaList + SystemZBuiltinVaList, + + // typedef struct __va_list_tag { + // void *__current_saved_reg_area_pointer; + // void *__saved_reg_area_end_pointer; + // void *__overflow_area_pointer; + //} va_list; + HexagonBuiltinVaList }; protected: @@ -656,6 +665,8 @@ class TargetInfo : public virtual TransferrableTargetInfo, /// types for the given target. unsigned getSimdDefaultAlign() const { return SimdDefaultAlign; } + unsigned getMaxOpenCLWorkGroupSize() const { return MaxOpenCLWorkGroupSize; } + /// Return the alignment (in bits) of the thrown exception object. This is /// only meaningful for targets that allocate C++ exceptions in a system /// runtime, such as those using the Itanium C++ ABI. @@ -1127,10 +1138,10 @@ class TargetInfo : public virtual TransferrableTargetInfo, } struct BranchProtectionInfo { - CodeGenOptions::SignReturnAddressScope SignReturnAddr = - CodeGenOptions::SignReturnAddressScope::None; - CodeGenOptions::SignReturnAddressKeyValue SignKey = - CodeGenOptions::SignReturnAddressKeyValue::AKey; + LangOptions::SignReturnAddressScopeKind SignReturnAddr = + LangOptions::SignReturnAddressScopeKind::None; + LangOptions::SignReturnAddressKeyKind SignKey = + LangOptions::SignReturnAddressKeyKind::AKey; bool BranchTargetEnforcement = false; }; @@ -1206,6 +1217,10 @@ class TargetInfo : public virtual TransferrableTargetInfo, "cpu_specific Multiversioning not implemented on this target"); } + // Get the cache line size of a given cpu. This method switches over + // the given cpu and returns "None" if the CPU is not found. + virtual Optional getCPUCacheLineSize() const { return None; } + // Returns maximal number of args passed in registers. unsigned getRegParmMax() const { assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); diff --git a/clang/include/clang/Basic/arm_cde.td b/clang/include/clang/Basic/arm_cde.td index e258bf5ee83e5..6a00e669864c8 100644 --- a/clang/include/clang/Basic/arm_cde.td +++ b/clang/include/clang/Basic/arm_cde.td @@ -189,6 +189,40 @@ def vcx3qa : FunctionMacro< "__arm_vcx3qa_impl((cp), (acc), __arm_vreinterpretq_u8(n), " "__arm_vreinterpretq_u8(m), (imm))">; +class CDEIntrinsicMasked + : CDEIntrinsic + $cp, $inactive_or_acc), cgArgs, (? $imm, $pred))> { + let params = T.All; + let polymorphicOnly = 1; +} + +def vcx1q_m : CDEIntrinsicMasked<"vcx1q", (args), (args imm_12b:$imm), (?)>; +def vcx1qa_m : CDEIntrinsicMasked<"vcx1qa", (args), (args imm_12b:$imm), (?)>; + +multiclass VCXPredicated macroArgs, string macro> { + def _m_impl : CDEIntrinsicMasked; + def a_m_impl : CDEIntrinsicMasked; + + def _m: FunctionMacro< + !listconcat(["cp", "inactive"], macroArgs, ["imm", "pred"]), + "__arm_"#NAME#"_m_impl((cp), (inactive), "#macro#" (imm), (pred))">; + def a_m: FunctionMacro< + !listconcat(["cp", "acc"], macroArgs, ["imm", "pred"]), + "__arm_"#NAME#"a_m_impl((cp), (acc), "#macro#" (imm), (pred))">; +} + +defm vcx2q : + VCXPredicated<(args v16u8:$n), (args imm_7b:$imm), (? $n), ["n"], + "__arm_vreinterpretq_u8(n),">; +defm vcx3q : + VCXPredicated<(args v16u8:$n, v16u8:$m), (args imm_4b:$imm), (? $n, $m), + ["n", "m"], "__arm_vreinterpretq_u8(n), " + "__arm_vreinterpretq_u8(m),">; + // vreinterpretq intrinsics required by the ACLE CDE specification foreach desttype = [/* no u8 */ s8, u16, s16, u32, s32, u64, s64, f16, f32] in { diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h index 31f0cea572324..5f4af7fd2a367 100644 --- a/clang/include/clang/CodeGen/CodeGenABITypes.h +++ b/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -28,11 +28,12 @@ #include "clang/CodeGen/CGFunctionInfo.h" namespace llvm { - class DataLayout; - class Module; - class Function; - class FunctionType; - class Type; +class Constant; +class DataLayout; +class Module; +class Function; +class FunctionType; +class Type; } namespace clang { @@ -44,6 +45,7 @@ class CoverageSourceInfo; class DiagnosticsEngine; class HeaderSearchOptions; class ObjCMethodDecl; +class ObjCProtocolDecl; class PreprocessorOptions; namespace CodeGen { @@ -137,6 +139,13 @@ llvm::Function *getNonTrivialCStructDestructor(CodeGenModule &CGM, CharUnits DstAlignment, bool IsVolatile, QualType QT); +/// Get a pointer to a protocol object for the given declaration, emitting it if +/// it hasn't already been emitted in this translation unit. Note that the ABI +/// for emitting a protocol reference in code (e.g. for a protocol expression) +/// in most runtimes is not as simple as just materializing a pointer to this +/// object. +llvm::Constant *emitObjCProtocolObject(CodeGenModule &CGM, + const ObjCProtocolDecl *p); } // end namespace CodeGen } // end namespace clang diff --git a/clang/include/clang/Config/config.h.cmake b/clang/include/clang/Config/config.h.cmake index 261b3841b86f8..26e9d5c4eb4d3 100644 --- a/clang/include/clang/Config/config.h.cmake +++ b/clang/include/clang/Config/config.h.cmake @@ -35,6 +35,9 @@ /* Default architecture for OpenMP offloading to Nvidia GPUs. */ #define CLANG_OPENMP_NVPTX_DEFAULT_ARCH "${CLANG_OPENMP_NVPTX_DEFAULT_ARCH}" +/* Default architecture for SystemZ. */ +#define CLANG_SYSTEMZ_DEFAULT_ARCH "${CLANG_SYSTEMZ_DEFAULT_ARCH}" + /* Multilib suffix for libdir. */ #define CLANG_LIBDIR_SUFFIX "${CLANG_LIBDIR_SUFFIX}" diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td index 2224c152f6266..218404e264095 100644 --- a/clang/include/clang/Driver/CC1Options.td +++ b/clang/include/clang/Driver/CC1Options.td @@ -282,8 +282,6 @@ def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">, HelpText<"Turn off struct-path aware Type Based Alias Analysis">; def new_struct_path_tbaa : Flag<["-"], "new-struct-path-tbaa">, HelpText<"Enable enhanced struct-path aware Type Based Alias Analysis">; -def masm_verbose : Flag<["-"], "masm-verbose">, - HelpText<"Generate verbose assembly output">; def mdebug_pass : Separate<["-"], "mdebug-pass">, HelpText<"Enable additional debug output">; def mframe_pointer_EQ : Joined<["-"], "mframe-pointer=">, @@ -455,8 +453,6 @@ def fspell_checking_limit : Separate<["-"], "fspell-checking-limit">, MetaVarNam def fcaret_diagnostics_max_lines : Separate<["-"], "fcaret-diagnostics-max-lines">, MetaVarName<"">, HelpText<"Set the maximum number of source lines to show in a caret diagnostic">; -def fmessage_length : Separate<["-"], "fmessage-length">, MetaVarName<"">, - HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; def verify_EQ : CommaJoined<["-"], "verify=">, MetaVarName<"">, HelpText<"Verify diagnostic output using comment directives that start with" diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 383a37bf57a1a..9b08a624682d2 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -590,13 +590,17 @@ def cuda_include_ptx_EQ : Joined<["--"], "cuda-include-ptx=">, Flags<[DriverOpti HelpText<"Include PTX for the following GPU architecture (e.g. sm_35) or 'all'. May be specified more than once.">; def no_cuda_include_ptx_EQ : Joined<["--"], "no-cuda-include-ptx=">, Flags<[DriverOption]>, HelpText<"Do not include PTX for the following GPU architecture (e.g. sm_35) or 'all'. May be specified more than once.">; +def offload_arch_EQ : Joined<["--"], "offload-arch=">, Flags<[DriverOption]>, + HelpText<"CUDA/HIP offloading device architecture (e.g. sm_35, gfx906). May be specified more than once.">; def cuda_gpu_arch_EQ : Joined<["--"], "cuda-gpu-arch=">, Flags<[DriverOption]>, - HelpText<"CUDA GPU architecture (e.g. sm_35). May be specified more than once.">; + Alias; def hip_link : Flag<["--"], "hip-link">, HelpText<"Link clang-offload-bundler bundles for HIP">; -def no_cuda_gpu_arch_EQ : Joined<["--"], "no-cuda-gpu-arch=">, Flags<[DriverOption]>, - HelpText<"Remove GPU architecture (e.g. sm_35) from the list of GPUs to compile for. " +def no_offload_arch_EQ : Joined<["--"], "no-offload-arch=">, Flags<[DriverOption]>, + HelpText<"Remove CUDA/HIP offloading device architecture (e.g. sm_35, gfx906) from the list of devices to compile for. " "'all' resets the list to its default value.">; +def no_cuda_gpu_arch_EQ : Joined<["--"], "no-cuda-gpu-arch=">, Flags<[DriverOption]>, + Alias; def cuda_noopt_device_debug : Flag<["--"], "cuda-noopt-device-debug">, HelpText<"Enable device-side debug info generation. Disables ptxas optimizations.">; def no_cuda_version_check : Flag<["--"], "no-cuda-version-check">, @@ -914,7 +918,7 @@ def fdiagnostics_hotness_threshold_EQ : Joined<["-"], "fdiagnostics-hotness-thre Group, Flags<[CC1Option]>, MetaVarName<"">, HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count">; def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group, - Flags<[CC1Option]>, HelpText<"Print option name with mappable diagnostics">; + HelpText<"Print option name with mappable diagnostics">; def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">, Group, Flags<[CC1Option]>, HelpText<"Display include stacks for diagnostic notes">; def fdiagnostics_format_EQ : Joined<["-"], "fdiagnostics-format=">, Group; @@ -1264,8 +1268,10 @@ 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, + HelpText<"Enables the global instruction selector">; def fexperimental_isel : Flag<["-"], "fexperimental-isel">, Group, - HelpText<"Enables the experimental global instruction selector">; + Alias; def fexperimental_new_pass_manager : Flag<["-"], "fexperimental-new-pass-manager">, Group, Flags<[CC1Option]>, HelpText<"Enables an experimental new pass manager in LLVM.">; @@ -1377,7 +1383,8 @@ def fmacro_backtrace_limit_EQ : Joined<["-"], "fmacro-backtrace-limit=">, Group, Flags<[DriverOption, CoreOption]>; def fmerge_all_constants : Flag<["-"], "fmerge-all-constants">, Group, Flags<[CC1Option, CoreOption]>, HelpText<"Allow merging of constants">; -def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group; +def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group, Flags<[CC1Option]>, + HelpText<"Format message diagnostics so that they fit within N columns">; def fms_extensions : Flag<["-"], "fms-extensions">, Group, Flags<[CC1Option, CoreOption]>, HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">; def fms_compatibility : Flag<["-"], "fms-compatibility">, Group, Flags<[CC1Option, CoreOption]>, @@ -1527,7 +1534,7 @@ def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group, def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, Group, Flags<[CC1Option]>, HelpText<"Do not include fixit information in diagnostics">; def fno_diagnostics_show_hotness : Flag<["-"], "fno-diagnostics-show-hotness">, Group; -def fno_diagnostics_show_option : Flag<["-"], "fno-diagnostics-show-option">, Group; +def fno_diagnostics_show_option : Flag<["-"], "fno-diagnostics-show-option">, Group, Flags<[CC1Option]>; def fno_diagnostics_show_note_include_stack : Flag<["-"], "fno-diagnostics-show-note-include-stack">, Flags<[CC1Option]>, Group; def fdigraphs : Flag<["-"], "fdigraphs">, Group, Flags<[CC1Option]>, @@ -1545,8 +1552,10 @@ def fno_exceptions : Flag<["-"], "fno-exceptions">, Group; def fno_gnu_keywords : Flag<["-"], "fno-gnu-keywords">, Group, Flags<[CC1Option]>; def fno_inline_functions : Flag<["-"], "fno-inline-functions">, Group, Flags<[CC1Option]>; def fno_inline : Flag<["-"], "fno-inline">, Group, Flags<[CC1Option]>; +def fno_global_isel : Flag<["-"], "fno-global-isel">, Group, + HelpText<"Disables the global instruction selector">; def fno_experimental_isel : Flag<["-"], "fno-experimental-isel">, Group, - HelpText<"Disables the experimental global instruction selector">; + Alias; def fno_experimental_new_pass_manager : Flag<["-"], "fno-experimental-new-pass-manager">, Group, Flags<[CC1Option]>, HelpText<"Disables an experimental new pass manager in LLVM.">; @@ -1618,7 +1627,7 @@ def fno_register_global_dtors_with_atexit : Flag<["-"], "fno-register-global-dto HelpText<"Don't use atexit or __cxa_atexit to register global destructors">; def fno_unit_at_a_time : Flag<["-"], "fno-unit-at-a-time">, Group; def fno_unwind_tables : Flag<["-"], "fno-unwind-tables">, Group; -def fno_verbose_asm : Flag<["-"], "fno-verbose-asm">, Group; +def fno_verbose_asm : Flag<["-"], "fno-verbose-asm">, Group, Flags<[CC1Option]>; def fno_working_directory : Flag<["-"], "fno-working-directory">, Group; def fno_wrapv : Flag<["-"], "fno-wrapv">, Group; def fno_zero_initialized_in_bss : Flag<["-"], "fno-zero-initialized-in-bss">, Group; @@ -1975,7 +1984,8 @@ def fuse_init_array : Flag<["-"], "fuse-init-array">, Group, def fno_use_init_array : Flag<["-"], "fno-use-init-array">, Group, Flags<[CC1Option]>, HelpText<"Don't use .init_array instead of .ctors">; def fno_var_tracking : Flag<["-"], "fno-var-tracking">, Group; -def fverbose_asm : Flag<["-"], "fverbose-asm">, Group; +def fverbose_asm : Flag<["-"], "fverbose-asm">, Group, + HelpText<"Generate verbose assembly output">; def dA : Flag<["-"], "dA">, Alias; def fvisibility_EQ : Joined<["-"], "fvisibility=">, Group, HelpText<"Set the default symbol visibility for all global declarations">, Values<"hidden,default">; @@ -2356,6 +2366,14 @@ def mspeculative_load_hardening : Flag<["-"], "mspeculative-load-hardening">, Group, Flags<[CoreOption,CC1Option]>; def mno_speculative_load_hardening : Flag<["-"], "mno-speculative-load-hardening">, Group, Flags<[CoreOption]>; +def mlvi_hardening : Flag<["-"], "mlvi-hardening">, Group, Flags<[CoreOption,DriverOption]>, + HelpText<"Enable all mitigations for Load Value Injection (LVI)">; +def mno_lvi_hardening : Flag<["-"], "mno-lvi-hardening">, Group, Flags<[CoreOption,DriverOption]>, + HelpText<"Disable mitigations for Load Value Injection (LVI)">; +def mlvi_cfi : Flag<["-"], "mlvi-cfi">, Group, Flags<[CoreOption,DriverOption]>, + HelpText<"Enable only control-flow mitigations for Load Value Injection (LVI)">; +def mno_lvi_cfi : Flag<["-"], "mno-lvi-cfi">, Group, Flags<[CoreOption,DriverOption]>, + HelpText<"Disable control-flow mitigations for Load Value Injection (LVI)">; def mrelax : Flag<["-"], "mrelax">, Group, HelpText<"Enable linker relaxation">; @@ -3265,6 +3283,8 @@ def mrdseed : Flag<["-"], "mrdseed">, Group; def mno_rdseed : Flag<["-"], "mno-rdseed">, Group; def msahf : Flag<["-"], "msahf">, Group; def mno_sahf : Flag<["-"], "mno-sahf">, Group; +def mserialize : Flag<["-"], "mserialize">, Group; +def mno_serialize : Flag<["-"], "mno-serialize">, Group; def msgx : Flag<["-"], "msgx">, Group; def mno_sgx : Flag<["-"], "mno-sgx">, Group; def msha : Flag<["-"], "msha">, Group; diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index f3253d5b40e3c..25476f78a6a00 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -59,8 +59,7 @@ class TargetOptions; /// report the error(s). bool ParseDiagnosticArgs(DiagnosticOptions &Opts, llvm::opt::ArgList &Args, DiagnosticsEngine *Diags = nullptr, - bool DefaultDiagColor = true, - bool DefaultShowOpt = true); + bool DefaultDiagColor = true); class CompilerInvocationBase { public: diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h index e994e24cf5afa..c9f9f080c1413 100644 --- a/clang/include/clang/Frontend/FrontendAction.h +++ b/clang/include/clang/Frontend/FrontendAction.h @@ -312,6 +312,7 @@ class WrapperFrontendAction : public FrontendAction { bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; void EndSourceFileAction() override; + bool shouldEraseOutputFiles() override; public: /// Construct a WrapperFrontendAction from an existing action, taking diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h index 89ac20075fa45..9ca2bfda21389 100644 --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -119,17 +119,13 @@ class GenerateModuleAction : public ASTFrontendAction { bool hasASTFileSupport() const override { return false; } }; -class GenerateInterfaceStubAction : public ASTFrontendAction { -protected: - TranslationUnitKind getTranslationUnitKind() override { return TU_Module; } - - bool hasASTFileSupport() const override { return false; } -}; - -class GenerateInterfaceIfsExpV1Action : public GenerateInterfaceStubAction { +class GenerateInterfaceStubsAction : public ASTFrontendAction { protected: std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; + + TranslationUnitKind getTranslationUnitKind() override { return TU_Module; } + bool hasASTFileSupport() const override { return false; } }; class GenerateModuleFromModuleMapAction : public GenerateModuleAction { diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 66fec6436a404..6069b5eea2650 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -90,7 +90,7 @@ enum ActionKind { GeneratePCH, /// Generate Interface Stub Files. - GenerateInterfaceIfsExpV1, + GenerateInterfaceStubs, /// Only execute frontend initialization. InitOnly, diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index b6f65227ab2eb..8abcc73e83d39 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -13,7 +13,6 @@ #ifndef LLVM_CLANG_PARSE_PARSER_H #define LLVM_CLANG_PARSE_PARSER_H -#include "clang/AST/OpenMPClause.h" #include "clang/AST/Availability.h" #include "clang/Basic/BitmaskEnum.h" #include "clang/Basic/OpenMPKinds.h" @@ -24,6 +23,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Frontend/OpenMP/OMPContext.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/SaveAndRestore.h" @@ -49,6 +49,10 @@ namespace clang { class OMPClause; class ObjCTypeParamList; class ObjCTypeParameter; + struct OMPTraitProperty; + struct OMPTraitSelector; + struct OMPTraitSet; + class OMPTraitInfo; /// Parser - This implements a parser for the C family of languages. After /// parsing units of the grammar, productions are invoked to handle whatever has @@ -763,13 +767,17 @@ class Parser : public CodeCompletionHandler { } /// getTypeAnnotation - Read a parsed type out of an annotation token. - static ParsedType getTypeAnnotation(const Token &Tok) { + static TypeResult getTypeAnnotation(const Token &Tok) { + if (!Tok.getAnnotationValue()) + return TypeError(); return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue()); } private: - static void setTypeAnnotation(Token &Tok, ParsedType T) { - Tok.setAnnotationValue(T.getAsOpaquePtr()); + static void setTypeAnnotation(Token &Tok, TypeResult T) { + assert((T.isInvalid() || T.get()) && + "produced a valid-but-null type annotation?"); + Tok.setAnnotationValue(T.isInvalid() ? nullptr : T.get().getAsOpaquePtr()); } static NamedDecl *getNonTypeAnnotation(const Token &Tok) { @@ -2940,45 +2948,66 @@ class Parser : public CodeCompletionHandler { /// Parse a property kind into \p TIProperty for the selector set \p Set and /// selector \p Selector. - void parseOMPTraitPropertyKind(OMPTraitInfo::OMPTraitProperty &TIProperty, + void parseOMPTraitPropertyKind(OMPTraitProperty &TIProperty, llvm::omp::TraitSet Set, llvm::omp::TraitSelector Selector, llvm::StringMap &Seen); /// Parse a selector kind into \p TISelector for the selector set \p Set. - void parseOMPTraitSelectorKind(OMPTraitInfo::OMPTraitSelector &TISelector, + void parseOMPTraitSelectorKind(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &Seen); /// Parse a selector set kind into \p TISet. - void parseOMPTraitSetKind(OMPTraitInfo::OMPTraitSet &TISet, + void parseOMPTraitSetKind(OMPTraitSet &TISet, llvm::StringMap &Seen); /// Parses an OpenMP context property. - void parseOMPContextProperty(OMPTraitInfo::OMPTraitSelector &TISelector, + void parseOMPContextProperty(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &Seen); /// Parses an OpenMP context selector. - void parseOMPContextSelector(OMPTraitInfo::OMPTraitSelector &TISelector, + void parseOMPContextSelector(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &SeenSelectors); /// Parses an OpenMP context selector set. - void parseOMPContextSelectorSet(OMPTraitInfo::OMPTraitSet &TISet, + void parseOMPContextSelectorSet(OMPTraitSet &TISet, llvm::StringMap &SeenSets); /// Parses OpenMP context selectors. bool parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI); + /// Parse a `match` clause for an '#pragma omp declare variant'. Return true + /// if there was an error. + bool parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI); + /// Parse clauses for '#pragma omp declare variant'. void ParseOMPDeclareVariantClauses(DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc); + /// Parse clauses for '#pragma omp declare target'. DeclGroupPtrTy ParseOMPDeclareTargetClauses(); /// Parse '#pragma omp end declare target'. void ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, SourceLocation Loc); + + /// Skip tokens until a `annot_pragma_openmp_end` was found. Emit a warning if + /// it is not the current token. + void skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind); + + /// Check the \p FoundKind against the \p ExpectedKind, if not issue an error + /// that the "end" matching the "begin" directive of kind \p BeginKind was not + /// found. Finally, if the expected kind was found or if \p SkipUntilOpenMPEnd + /// is set, skip ahead using the helper `skipUntilPragmaOpenMPEnd`. + void parseOMPEndDirective(OpenMPDirectiveKind BeginKind, + OpenMPDirectiveKind ExpectedKind, + OpenMPDirectiveKind FoundKind, + SourceLocation MatchingLoc, + SourceLocation FoundLoc, + bool SkipUntilOpenMPEnd); + /// Parses declarative OpenMP directives. DeclGroupPtrTy ParseOpenMPDeclarativeDirectiveWithExtDecl( AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, @@ -2997,6 +3026,10 @@ class Parser : public CodeCompletionHandler { DeclarationName &Name, AccessSpecifier AS = AS_none); + /// Tries to parse cast part of OpenMP array shaping operation: + /// '[' expression ']' { '[' expression ']' } ')'. + bool tryParseOpenMPArrayShapingCastPart(); + /// Parses simple list of variables. /// /// \param Kind Kind of the directive. @@ -3065,6 +3098,11 @@ class Parser : public CodeCompletionHandler { OMPClause *ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, bool ParseOnly); + /// Parses and creates OpenMP 5.0 iterators expression: + /// = 'iterator' '(' { [ ] identifier = + /// }+ ')' + ExprResult ParseOpenMPIteratorsExpr(); + public: /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. @@ -3074,16 +3112,16 @@ class Parser : public CodeCompletionHandler { /// Data used for parsing list of variables in OpenMP clauses. struct OpenMPVarListDataTy { - Expr *TailExpr = nullptr; + Expr *DepModOrTailExpr = nullptr; SourceLocation ColonLoc; SourceLocation RLoc; CXXScopeSpec ReductionOrMapperIdScopeSpec; DeclarationNameInfo ReductionOrMapperId; int ExtraModifier = -1; ///< Additional modifier for linear, map, depend or ///< lastprivate clause. - SmallVector + SmallVector MapTypeModifiers; - SmallVector + SmallVector MapTypeModifiersLoc; bool IsMapTypeImplicit = false; SourceLocation ExtraModifierLoc; @@ -3147,7 +3185,8 @@ class Parser : public CodeCompletionHandler { // C++ 14.3: Template arguments [temp.arg] typedef SmallVector TemplateArgList; - bool ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, + bool ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, + SourceLocation &RAngleLoc, bool ConsumeLastToken, bool ObjCGenericList); bool ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 5a6bedcd6f59d..78010b7bb46e6 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -667,6 +667,13 @@ class DeclSpec { bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, ParsedType Rep, const PrintingPolicy &Policy); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, TypeResult Rep, + const PrintingPolicy &Policy) { + if (Rep.isInvalid()) + return SetTypeSpecError(); + return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Rep.get(), Policy); + } bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned, const PrintingPolicy &Policy); diff --git a/clang/include/clang/Sema/Ownership.h b/clang/include/clang/Sema/Ownership.h index 4de3397d51b45..7c7b1d35c9fd5 100644 --- a/clang/include/clang/Sema/Ownership.h +++ b/clang/include/clang/Sema/Ownership.h @@ -278,6 +278,7 @@ namespace clang { inline ExprResult ExprError() { return ExprResult(true); } inline StmtResult StmtError() { return StmtResult(true); } + inline TypeResult TypeError() { return TypeResult(true); } inline ExprResult ExprError(const DiagnosticBuilder&) { return ExprError(); } inline StmtResult StmtError(const DiagnosticBuilder&) { return StmtError(); } diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index e1e63ed87896b..98671bf06ab12 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -63,9 +63,9 @@ struct ParsedAttrInfo { /// The syntaxes supported by this attribute and how they're spelled. struct Spelling { AttributeCommonInfo::Syntax Syntax; - std::string NormalizedFullName; + const char *NormalizedFullName; }; - std::vector Spellings; + ArrayRef Spellings; ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind = AttributeCommonInfo::NoSemaHandlerAttribute) diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h index 82d00494b0d6b..f0245b93c7eb2 100644 --- a/clang/include/clang/Sema/ParsedTemplate.h +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -169,7 +169,9 @@ namespace clang { /// template-name. ParsedTemplateTy Template; - /// The kind of template that Template refers to. + /// The kind of template that Template refers to. If this is + /// TNK_Non_template, an error was encountered and diagnosed + /// when parsing or looking up the template name. TemplateNameKind Kind; /// The location of the '<' before the template argument @@ -183,6 +185,10 @@ namespace clang { /// NumArgs - The number of template arguments. unsigned NumArgs; + /// Whether an error was encountered in the template arguments. + /// If so, NumArgs and the trailing arguments are best-effort. + bool ArgsInvalid; + /// Retrieves a pointer to the template arguments ParsedTemplateArgument *getTemplateArgs() { return getTrailingObjects(); @@ -195,13 +201,13 @@ namespace clang { IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, SourceLocation LAngleLoc, SourceLocation RAngleLoc, - ArrayRef TemplateArgs, + ArrayRef TemplateArgs, bool ArgsInvalid, SmallVectorImpl &CleanupList) { TemplateIdAnnotation *TemplateId = new (llvm::safe_malloc( totalSizeToAlloc(TemplateArgs.size()))) TemplateIdAnnotation(TemplateKWLoc, TemplateNameLoc, Name, OperatorKind, OpaqueTemplateName, TemplateKind, - LAngleLoc, RAngleLoc, TemplateArgs); + LAngleLoc, RAngleLoc, TemplateArgs, ArgsInvalid); CleanupList.push_back(TemplateId); return TemplateId; } @@ -213,6 +219,20 @@ namespace clang { this->~TemplateIdAnnotation(); free(this); } + + /// Determine whether this might be a type template. + bool mightBeType() const { + return Kind == TNK_Non_template || + Kind == TNK_Type_template || + Kind == TNK_Dependent_template_name || + Kind == TNK_Undeclared_template; + } + + bool hasInvalidName() const { return Kind == TNK_Non_template; } + bool hasInvalidArgs() const { return ArgsInvalid; } + + bool isInvalid() const { return hasInvalidName() || hasInvalidArgs(); } + private: TemplateIdAnnotation(const TemplateIdAnnotation &) = delete; @@ -222,11 +242,12 @@ namespace clang { ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, SourceLocation LAngleLoc, SourceLocation RAngleLoc, - ArrayRef TemplateArgs) noexcept + ArrayRef TemplateArgs, + bool ArgsInvalid) noexcept : TemplateKWLoc(TemplateKWLoc), TemplateNameLoc(TemplateNameLoc), Name(Name), Operator(OperatorKind), Template(OpaqueTemplateName), Kind(TemplateKind), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), - NumArgs(TemplateArgs.size()) { + NumArgs(TemplateArgs.size()), ArgsInvalid(ArgsInvalid) { std::uninitialized_copy(TemplateArgs.begin(), TemplateArgs.end(), getTemplateArgs()); diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 6133425a42a62..169ca175eed22 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -320,9 +320,7 @@ class Scope { /// isDeclScope - Return true if this is the scope that the specified decl is /// declared in. - bool isDeclScope(Decl *D) { - return DeclsInScope.count(D) != 0; - } + bool isDeclScope(const Decl *D) const { return DeclsInScope.count(D) != 0; } DeclContext *getEntity() const { return Entity; } void setEntity(DeclContext *E) { Entity = E; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 17f90403b0ddb..6a4940539d3fc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -25,6 +25,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/MangleNumberingContext.h" @@ -58,6 +59,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" @@ -4976,7 +4978,7 @@ class Sema final { SourceLocation RParen, ParsedType Ty); ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, SourceLocation LParen, - SourceLocation RParen, Expr *Operand); + SourceLocation RParen, Expr *E); bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); @@ -5051,6 +5053,25 @@ class Sema final { ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc); + ExprResult ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef Dims, + ArrayRef Brackets); + + /// Data structure for iterator expression. + struct OMPIteratorData { + IdentifierInfo *DeclIdent = nullptr; + SourceLocation DeclIdentLoc; + ParsedType Type; + OMPIteratorExpr::IteratorRange Range; + SourceLocation AssignLoc; + SourceLocation ColonLoc; + SourceLocation SecColonLoc; + }; + + ExprResult ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, + SourceLocation LLoc, SourceLocation RLoc, + ArrayRef Data); // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after @@ -7151,6 +7172,27 @@ class Sema final { bool AllowFunctionTemplates = true, bool AllowDependent = true); + enum TemplateNameIsRequiredTag { TemplateNameIsRequired }; + /// Whether and why a template name is required in this lookup. + class RequiredTemplateKind { + public: + /// Template name is required if TemplateKWLoc is valid. + RequiredTemplateKind(SourceLocation TemplateKWLoc = SourceLocation()) + : TemplateKW(TemplateKWLoc) {} + /// Template name is unconditionally required. + RequiredTemplateKind(TemplateNameIsRequiredTag) : TemplateKW() {} + + SourceLocation getTemplateKeywordLoc() const { + return TemplateKW.getValueOr(SourceLocation()); + } + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + bool isRequired() const { return TemplateKW != SourceLocation(); } + explicit operator bool() const { return isRequired(); } + + private: + llvm::Optional TemplateKW; + }; + enum class AssumedTemplateKind { /// This is not assumed to be a template name. None, @@ -7160,12 +7202,11 @@ class Sema final { /// functions (but no function templates). FoundFunctions, }; - bool LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, - QualType ObjectType, bool EnteringContext, - bool &MemberOfUnknownSpecialization, - SourceLocation TemplateKWLoc = SourceLocation(), - AssumedTemplateKind *ATK = nullptr, - bool Disambiguation = false); + bool LookupTemplateName( + LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, + bool EnteringContext, bool &MemberOfUnknownSpecialization, + RequiredTemplateKind RequiredTemplate = SourceLocation(), + AssumedTemplateKind *ATK = nullptr, bool AllowTypoCorrection = true); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, @@ -7378,7 +7419,7 @@ class Sema final { const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); - TemplateNameKind ActOnDependentTemplateName( + TemplateNameKind ActOnTemplateName( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool AllowInjectedClassName = false); @@ -9979,14 +10020,54 @@ class Sema final { MapT &Map, unsigned Selector = 0, SourceRange SrcRange = SourceRange()); - /// Marks all the functions that might be required for the currently active - /// OpenMP context. - void markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, - FunctionDecl *Func, - bool MightBeOdrUse); + /// Helper to keep information about the current `omp begin/end declare + /// variant` nesting. + struct OMPDeclareVariantScope { + /// The associated OpenMP context selector. + OMPTraitInfo *TI; + + /// The associated OpenMP context selector mangling. + std::string NameSuffix; + + OMPDeclareVariantScope(OMPTraitInfo &TI); + }; + + /// The current `omp begin/end declare variant` scopes. + SmallVector OMPDeclareVariantScopes; + + /// The declarator \p D defines a function in the scope \p S which is nested + /// in an `omp begin/end declare variant` scope. In this method we create a + /// declaration for \p D and rename \p D according to the OpenMP context + /// selector of the surrounding scope. + FunctionDecl * + ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S, + Declarator &D); + + /// Register \p FD as specialization of \p BaseFD in the current `omp + /// begin/end declare variant` scope. + void ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( + FunctionDecl *FD, FunctionDecl *BaseFD); public: - /// Struct to store the context selectors info for declare variant directive. + + /// Can we exit a scope at the moment. + bool isInOpenMPDeclareVariantScope() { + return !OMPDeclareVariantScopes.empty(); + } + + /// Given the potential call expression \p Call, determine if there is a + /// specialization via the OpenMP declare variant mechanism available. If + /// there is, return the specialized call expression, otherwise return the + /// original \p Call. + ExprResult ActOnOpenMPCall(Sema &S, ExprResult Call, Scope *Scope, + SourceLocation LParenLoc, MultiExprArg ArgExprs, + SourceLocation RParenLoc, Expr *ExecConfig); + + /// Handle a `omp begin declare variant`. + void ActOnOpenMPBeginDeclareVariant(SourceLocation Loc, OMPTraitInfo &TI); + + /// Handle a `omp end declare variant`. + void ActOnOpenMPEndDeclareVariant(); /// Checks if the variant/multiversion functions are compatible. bool areMultiversionVariantFunctionsCompatible( @@ -10674,7 +10755,7 @@ class Sema final { SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPVarListClause( - OpenMPClauseKind Kind, ArrayRef Vars, Expr *TailExpr, + OpenMPClauseKind Kind, ArrayRef Vars, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, @@ -10772,10 +10853,10 @@ class Sema final { SourceLocation EndLoc); /// Called on well-formed 'depend' clause. OMPClause * - ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, - SourceLocation ColonLoc, ArrayRef VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc); + ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'device' clause. OMPClause *ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier, Expr *Device, SourceLocation StartLoc, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index f185c1a16834b..e6e9c8570cc8b 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1016,6 +1016,12 @@ namespace serialization { /// \brief The '_Sat unsigned long _Fract' type PREDEF_TYPE_SAT_ULONG_FRACT_ID = 69, + /// The placeholder type for OpenMP array shaping operation. + PREDEF_TYPE_OMP_ARRAY_SHAPING = 70, + + /// The placeholder type for OpenMP iterator expression. + PREDEF_TYPE_OMP_ITERATOR = 71, + /// OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, @@ -1868,6 +1874,8 @@ namespace serialization { STMT_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE, STMT_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE, EXPR_OMP_ARRAY_SECTION, + EXPR_OMP_ARRAY_SHAPING, + EXPR_OMP_ITERATOR, // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr diff --git a/clang/include/clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h b/clang/include/clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h index c7732333d9baf..e2be957821b99 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h +++ b/clang/include/clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h @@ -28,7 +28,7 @@ class CheckerRegistry; #define GET_CHECKERS #define CHECKER(FULLNAME, CLASS, HELPTEXT, DOC_URI, IS_HIDDEN) \ void register##CLASS(CheckerManager &mgr); \ - bool shouldRegister##CLASS(const LangOptions &LO); + bool shouldRegister##CLASS(const CheckerManager &mgr); #include "clang/StaticAnalyzer/Checkers/Checkers.inc" #undef CHECKER #undef GET_CHECKERS diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index a21107cd4c2df..6a577940e3138 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -299,7 +299,7 @@ def StdCLibraryFunctionArgsChecker : Checker<"StdCLibraryFunctionArgs">, HelpText<"Check constraints of arguments of C standard library functions, " "such as whether the parameter of isalpha is in the range [0, 255] " "or is EOF.">, - Dependencies<[StdCLibraryFunctionsChecker]>, + Dependencies<[StdCLibraryFunctionsChecker, CallAndMessageChecker]>, Documentation; def TrustNonnullChecker : Checker<"TrustNonnull">, @@ -1422,6 +1422,12 @@ def DebugIteratorModeling : Checker<"DebugIteratorModeling">, Dependencies<[DebugContainerModeling, IteratorModeling]>, Documentation; +def StdCLibraryFunctionsTesterChecker : Checker<"StdCLibraryFunctionsTester">, + HelpText<"Add test functions to the summary map, so testing of individual " + "summary constituents becomes possible.">, + Dependencies<[StdCLibraryFunctionsChecker]>, + Documentation; + } // end "debug" diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 4454d7603b27f..f34f5c2392902 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERMANAGER_H #include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" @@ -121,14 +122,38 @@ enum class ObjCMessageVisitKind { }; class CheckerManager { - ASTContext &Context; + ASTContext *Context = nullptr; const LangOptions LangOpts; - AnalyzerOptions &AOptions; + const AnalyzerOptions &AOptions; + const Preprocessor *PP = nullptr; CheckerNameRef CurrentCheckerName; + DiagnosticsEngine &Diags; + std::unique_ptr Registry; public: - CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions) - : Context(Context), LangOpts(Context.getLangOpts()), AOptions(AOptions) {} + // These constructors are defined in the Frontend library, because + // CheckerRegistry, a crucial component of the initialization is in there. + // CheckerRegistry cannot be moved to the Core library, because the checker + // registration functions are defined in the Checkers library, and the library + // dependencies look like this: Core -> Checkers -> Frontend. + + CheckerManager( + ASTContext &Context, AnalyzerOptions &AOptions, const Preprocessor &PP, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns); + + /// Constructs a CheckerManager that ignores all non TblGen-generated + /// checkers. Useful for unit testing, unless the checker infrastructure + /// itself is tested. + CheckerManager(ASTContext &Context, AnalyzerOptions &AOptions, + const Preprocessor &PP) + : CheckerManager(Context, AOptions, PP, {}, {}) {} + + /// Constructs a CheckerManager without requiring an AST. No checker + /// registration will take place. Only useful for retrieving the + /// CheckerRegistry and print for help flags where the AST is unavalaible. + CheckerManager(AnalyzerOptions &AOptions, const LangOptions &LangOpts, + DiagnosticsEngine &Diags, ArrayRef plugins); ~CheckerManager(); @@ -140,8 +165,17 @@ class CheckerManager { void finishedCheckerRegistration(); const LangOptions &getLangOpts() const { return LangOpts; } - AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } - ASTContext &getASTContext() const { return Context; } + const AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } + const Preprocessor &getPreprocessor() const { + assert(PP); + return *PP; + } + const CheckerRegistry &getCheckerRegistry() const { return *Registry; } + DiagnosticsEngine &getDiagnostics() const { return Diags; } + ASTContext &getASTContext() const { + assert(Context); + return *Context; + } /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h index 2d24e6a9586b7..bcc29a60ad703 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -55,7 +55,7 @@ class AnalysisASTConsumer : public ASTConsumer { std::unique_ptr CreateAnalysisConsumer(CompilerInstance &CI); -} // end GR namespace +} // namespace ento } // end clang namespace diff --git a/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h b/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h new file mode 100644 index 0000000000000..a30c241e13502 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h @@ -0,0 +1,30 @@ +//===-- AnalyzerHelpFlags.h - Query functions for --help flags --*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H +#define LLVM_CLANG_STATICANALYZER_FRONTEND_ANALYZERHELPFLAGS_H + +namespace llvm { +class raw_ostream; +} // namespace llvm + +namespace clang { + +class CompilerInstance; + +namespace ento { + +void printCheckerHelp(llvm::raw_ostream &OS, CompilerInstance &CI); +void printEnabledCheckerList(llvm::raw_ostream &OS, CompilerInstance &CI); +void printAnalyzerConfigList(llvm::raw_ostream &OS); +void printCheckerConfigList(llvm::raw_ostream &OS, CompilerInstance &CI); + +} // namespace ento +} // namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h deleted file mode 100644 index 52a534499002c..0000000000000 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h +++ /dev/null @@ -1,38 +0,0 @@ -//===-- CheckerRegistration.h - Checker Registration Function ---*- 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 -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H -#define LLVM_CLANG_STATICANALYZER_FRONTEND_CHECKERREGISTRATION_H - -#include "clang/AST/ASTContext.h" -#include "clang/Basic/LLVM.h" -#include -#include -#include - -namespace clang { - class AnalyzerOptions; - class LangOptions; - class DiagnosticsEngine; - -namespace ento { - class CheckerManager; - class CheckerRegistry; - - std::unique_ptr createCheckerManager( - ASTContext &context, - AnalyzerOptions &opts, - ArrayRef plugins, - ArrayRef> checkerRegistrationFns, - DiagnosticsEngine &diags); - -} // end ento namespace - -} // end namespace clang - -#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index 8830542f27d82..4e98ba2e10d23 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -10,7 +10,6 @@ #define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H #include "clang/Basic/LLVM.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -70,10 +69,11 @@ namespace clang { class AnalyzerOptions; class DiagnosticsEngine; -class LangOptions; namespace ento { +class CheckerManager; + /// Manages a set of available checkers for running a static analysis. /// The checkers are organized into packages by full name, where including /// a package will recursively include all subpackages and checkers within it. @@ -83,14 +83,19 @@ namespace ento { class CheckerRegistry { public: CheckerRegistry(ArrayRef plugins, DiagnosticsEngine &diags, - AnalyzerOptions &AnOpts, const LangOptions &LangOpts, + AnalyzerOptions &AnOpts, ArrayRef> checkerRegistrationFns = {}); + /// Collects all enabled checkers in the field EnabledCheckers. It preserves + /// the order of insertion, as dependencies have to be enabled before the + /// checkers that depend on them. + void initializeRegistry(const CheckerManager &Mgr); + /// Initialization functions perform any necessary setup for a checker. /// They should include a call to CheckerManager::registerChecker. using InitializationFunction = void (*)(CheckerManager &); - using ShouldRegisterFunction = bool (*)(const LangOptions &); + using ShouldRegisterFunction = bool (*)(const CheckerManager &); /// Specifies a command line option. It may either belong to a checker or a /// package. @@ -162,12 +167,12 @@ class CheckerRegistry { ConstCheckerInfoList Dependencies; - bool isEnabled(const LangOptions &LO) const { - return State == StateFromCmdLine::State_Enabled && ShouldRegister(LO); + bool isEnabled(const CheckerManager &mgr) const { + return State == StateFromCmdLine::State_Enabled && ShouldRegister(mgr); } - bool isDisabled(const LangOptions &LO) const { - return State == StateFromCmdLine::State_Disabled || !ShouldRegister(LO); + bool isDisabled(const CheckerManager &mgr) const { + return State == StateFromCmdLine::State_Disabled || !ShouldRegister(mgr); } // Since each checker must have a different full name, we can identify @@ -205,14 +210,20 @@ class CheckerRegistry { using PackageInfoList = llvm::SmallVector; - template static void addToCheckerMgr(CheckerManager &mgr) { - mgr.registerChecker(); +private: + /// Default initialization function for checkers -- since CheckerManager + /// includes this header, we need to make it a template parameter, and since + /// the checker must be a template parameter as well, we can't put this in the + /// cpp file. + template static void initializeManager(MGR &mgr) { + mgr.template registerChecker(); } - static bool returnTrue(const LangOptions &LO) { + template static bool returnTrue(const CheckerManager &mgr) { return true; } +public: /// Adds a checker to the registry. Use this non-templated overload when your /// checker requires custom initialization. void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, @@ -221,13 +232,17 @@ class CheckerRegistry { /// Adds a checker to the registry. Use this templated overload when your /// checker does not require any custom initialization. + /// This function isn't really needed and probably causes more headaches than + /// the tiny convenience that it provides, but external plugins might use it, + /// and there isn't a strong incentive to remove it. template void addChecker(StringRef FullName, StringRef Desc, StringRef DocsUri, bool IsHidden = false) { // Avoid MSVC's Compiler Error C2276: // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx - addChecker(&CheckerRegistry::addToCheckerMgr, - &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, IsHidden); + addChecker(&CheckerRegistry::initializeManager, + &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, + IsHidden); } /// Makes the checker with the full name \p fullName depends on the checker @@ -263,7 +278,7 @@ class CheckerRegistry { void addPackageOption(StringRef OptionType, StringRef PackageFullName, StringRef OptionName, StringRef DefaultValStr, StringRef Description, StringRef DevelopmentStatus, - bool IsHidden = false); + bool IsHidden = false); // FIXME: This *really* should be added to the frontend flag descriptions. /// Initializes a CheckerManager by calling the initialization functions for @@ -283,11 +298,6 @@ class CheckerRegistry { void printCheckerOptionList(raw_ostream &Out) const; private: - /// Collect all enabled checkers. The returned container preserves the order - /// of insertion, as dependencies have to be enabled before the checkers that - /// depend on them. - CheckerInfoSet getEnabledCheckers() const; - /// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to. /// For example, it'll return the checkers for the core package, if /// \p CmdLineArg is "core". @@ -314,7 +324,7 @@ class CheckerRegistry { DiagnosticsEngine &Diags; AnalyzerOptions &AnOpts; - const LangOptions &LangOpts; + CheckerInfoSet EnabledCheckers; }; } // namespace ento diff --git a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index 878b65a1b143c..2b12330e4f2db 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -20,6 +20,8 @@ class AnalyzerOptions; namespace ento { +class CheckerManager; + //===----------------------------------------------------------------------===// // AST Consumer Actions //===----------------------------------------------------------------------===// @@ -51,23 +53,7 @@ class ParseModelFileAction : public ASTFrontendAction { llvm::StringMap &Bodies; }; -void printCheckerHelp(raw_ostream &OS, - ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); -void printEnabledCheckerList(raw_ostream &OS, ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); -void printAnalyzerConfigList(raw_ostream &OS); -void printCheckerConfigList(raw_ostream &OS, ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts); - -} // end GR namespace - +} // namespace ento } // end namespace clang #endif diff --git a/clang/include/clang/Tooling/Syntax/Tokens.h b/clang/include/clang/Tooling/Syntax/Tokens.h index 2ee8400748108..7e50892284f4b 100644 --- a/clang/include/clang/Tooling/Syntax/Tokens.h +++ b/clang/include/clang/Tooling/Syntax/Tokens.h @@ -176,6 +176,12 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Token &T); class TokenBuffer { public: TokenBuffer(const SourceManager &SourceMgr) : SourceMgr(&SourceMgr) {} + + TokenBuffer(TokenBuffer &&) = default; + TokenBuffer(const TokenBuffer &) = delete; + TokenBuffer &operator=(TokenBuffer &&) = default; + TokenBuffer &operator=(const TokenBuffer &) = delete; + /// All tokens produced by the preprocessor after all macro replacements, /// directives, etc. Source locations found in the clang AST will always /// point to one of these tokens. @@ -191,18 +197,20 @@ class TokenBuffer { /// token range R. llvm::ArrayRef expandedTokens(SourceRange R) const; - /// Find the subrange of spelled tokens that produced the corresponding \p - /// Expanded tokens. + /// Returns the subrange of spelled tokens corresponding to AST node spanning + /// \p Expanded. This is the text that should be replaced if a refactoring + /// were to rewrite the node. If \p Expanded is empty, the returned value is + /// llvm::None. /// - /// EXPECTS: \p Expanded is a subrange of expandedTokens(). - /// - /// Will fail if the expanded tokens do not correspond to a - /// sequence of spelled tokens. E.g. for the following example: + /// Will fail if the expanded tokens do not correspond to a sequence of + /// spelled tokens. E.g. for the following example: /// /// #define FIRST f1 f2 f3 /// #define SECOND s1 s2 s3 + /// #define ID2(X, Y) X Y /// /// a FIRST b SECOND c // expanded tokens are: a f1 f2 f3 b s1 s2 s3 c + /// d ID2(e f g, h) i // expanded tokens are: d e f g h i /// /// the results would be: /// expanded => spelled @@ -212,8 +220,10 @@ class TokenBuffer { /// a f1 f2 f3 => a FIRST /// a f1 => can't map /// s1 s2 => can't map + /// e f => e f + /// g h => can't map /// - /// If \p Expanded is empty, the returned value is llvm::None. + /// EXPECTS: \p Expanded is a subrange of expandedTokens(). /// Complexity is logarithmic. llvm::Optional> spelledForExpanded(llvm::ArrayRef Expanded) const; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 29f028bfc2020..29b4c848ae2ce 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1391,8 +1391,11 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn); // Placeholder type for OMP array sections. - if (LangOpts.OpenMP) + if (LangOpts.OpenMP) { InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection); + InitBuiltinType(OMPArrayShapingTy, BuiltinType::OMPArrayShaping); + InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator); + } // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); @@ -2166,6 +2169,11 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { return getTypeInfo(cast(T)->getAdjustedType().getTypePtr()); case Type::ObjCInterface: { const auto *ObjCI = cast(T); + if (ObjCI->getDecl()->isInvalidDecl()) { + Width = 8; + Align = 8; + break; + } const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); @@ -7800,6 +7808,57 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) { return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list"); } +static TypedefDecl *CreateHexagonBuiltinVaListDecl(const ASTContext *Context) { + // typedef struct __va_list_tag { + RecordDecl *VaListTagDecl; + VaListTagDecl = Context->buildImplicitRecord("__va_list_tag"); + VaListTagDecl->startDefinition(); + + const size_t NumFields = 3; + QualType FieldTypes[NumFields]; + const char *FieldNames[NumFields]; + + // void *CurrentSavedRegisterArea; + FieldTypes[0] = Context->getPointerType(Context->VoidTy); + FieldNames[0] = "__current_saved_reg_area_pointer"; + + // void *SavedRegAreaEnd; + FieldTypes[1] = Context->getPointerType(Context->VoidTy); + FieldNames[1] = "__saved_reg_area_end_pointer"; + + // void *OverflowArea; + FieldTypes[2] = Context->getPointerType(Context->VoidTy); + FieldNames[2] = "__overflow_area_pointer"; + + // Create fields + for (unsigned i = 0; i < NumFields; ++i) { + FieldDecl *Field = FieldDecl::Create( + const_cast(*Context), VaListTagDecl, SourceLocation(), + SourceLocation(), &Context->Idents.get(FieldNames[i]), FieldTypes[i], + /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, ICIS_NoInit); + Field->setAccess(AS_public); + VaListTagDecl->addDecl(Field); + } + VaListTagDecl->completeDefinition(); + Context->VaListTagDecl = VaListTagDecl; + QualType VaListTagType = Context->getRecordType(VaListTagDecl); + + // } __va_list_tag; + TypedefDecl *VaListTagTypedefDecl = + Context->buildImplicitTypedef(VaListTagType, "__va_list_tag"); + + QualType VaListTagTypedefType = Context->getTypedefType(VaListTagTypedefDecl); + + // typedef __va_list_tag __builtin_va_list[1]; + llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1); + QualType VaListTagArrayType = Context->getConstantArrayType( + VaListTagTypedefType, Size, nullptr, ArrayType::Normal, 0); + + return Context->buildImplicitTypedef(VaListTagArrayType, "__builtin_va_list"); +} + static TypedefDecl *CreateVaListDecl(const ASTContext *Context, TargetInfo::BuiltinVaListKind Kind) { switch (Kind) { @@ -7819,6 +7878,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreateAAPCSABIBuiltinVaListDecl(Context); case TargetInfo::SystemZBuiltinVaList: return CreateSystemZBuiltinVaListDecl(Context); + case TargetInfo::HexagonBuiltinVaList: + return CreateHexagonBuiltinVaListDecl(Context); } llvm_unreachable("Unhandled __builtin_va_list type kind"); diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index a5ff68c187788..bc0db1ba10a2a 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -151,6 +151,11 @@ OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) { return llvm::None; } +namespace clang { +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo *TI); +} + void OMPDeclareVariantAttr::printPrettyPragma( raw_ostream &OS, const PrintingPolicy &Policy) const { if (const Expr *E = getVariantFuncRef()) { @@ -158,9 +163,7 @@ void OMPDeclareVariantAttr::printPrettyPragma( E->printPretty(OS, nullptr, Policy); OS << ")"; } - OS << " match("; - traitInfos->print(OS, Policy); - OS << ")"; + OS << " match(" << traitInfos << ")"; } #include "clang/AST/AttrImpl.inc" diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index a6ccf9aad321e..3a326f62a2ec3 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -172,7 +172,7 @@ ExprDependence clang::computeDependence(VAArgExpr *E) { ExprDependence clang::computeDependence(NoInitExpr *E) { return toExprDependence(E->getType()->getDependence()) & - (ExprDependence::Instantiation & ExprDependence::Error); + (ExprDependence::Instantiation | ExprDependence::Error); } ExprDependence clang::computeDependence(ArrayInitLoopExpr *E) { @@ -363,6 +363,31 @@ ExprDependence clang::computeDependence(OMPArraySectionExpr *E) { return D; } +ExprDependence clang::computeDependence(OMPArrayShapingExpr *E) { + auto D = E->getBase()->getDependence() | + toExprDependence(E->getType()->getDependence()); + for (Expr *Dim: E->getDimensions()) + if (Dim) + D |= Dim->getDependence(); + return D; +} + +ExprDependence clang::computeDependence(OMPIteratorExpr *E) { + auto D = toExprDependence(E->getType()->getDependence()); + for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) { + if (auto *VD = cast_or_null(E->getIteratorDecl(I))) + D |= toExprDependence(VD->getType()->getDependence()); + OMPIteratorExpr::IteratorRange IR = E->getIteratorRange(I); + if (Expr *BE = IR.Begin) + D |= BE->getDependence(); + if (Expr *EE = IR.End) + D |= EE->getDependence(); + if (Expr *SE = IR.Step) + D |= SE->getDependence(); + } + return D; +} + /// Compute the type-, value-, and instantiation-dependence of a /// declaration reference /// based on the declaration being referenced. @@ -370,7 +395,8 @@ ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) { auto Deps = ExprDependence::None; if (auto *NNS = E->getQualifier()) - Deps |= toExprDependence(NNS->getDependence()); + Deps |= toExprDependence(NNS->getDependence() & + ~NestedNameSpecifierDependence::Dependent); if (auto *FirstArg = E->getTemplateArgs()) { unsigned NumArgs = E->getNumTemplateArgs(); @@ -590,7 +616,8 @@ ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) { D |= turnTypeToValueDependence( toExprDependence(ST->getType()->getDependence())); if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence()); + D |= toExprDependence(Q->getDependence() & + ~NestedNameSpecifierDependence::Dependent); return D; } @@ -616,7 +643,8 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, Deps |= ExprDependence::UnexpandedPack; Deps |= getDependenceInExpr(E->getNameInfo()); if (auto *Q = E->getQualifier()) - Deps |= toExprDependence(Q->getDependence()); + Deps |= toExprDependence(Q->getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || isa(D)) diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index 4eb11bc57e521..ecf676c9936d1 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" @@ -138,8 +139,19 @@ void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) const { switch (getNameKind()) { case DeclarationName::Identifier: - if (const IdentifierInfo *II = getAsIdentifierInfo()) - OS << II->getName(); + if (const IdentifierInfo *II = getAsIdentifierInfo()) { + StringRef Name = II->getName(); + // If this is a mangled OpenMP variant name we strip off the mangling for + // printing. It should not be visible to the user at all. + if (II->isMangledOpenMPVariantName()) { + std::pair NameContextPair = + Name.split(getOpenMPVariantManglingSeparatorStr()); + OS << NameContextPair.first << "[" + << OMPTraitInfo(NameContextPair.second) << "]"; + } else { + OS << Name; + } + } return; case DeclarationName::ObjCZeroArgSelector: diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index b603d2ab29eed..d82381d611efa 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -522,7 +522,7 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK, } PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK, - Expr *Info) + Expr *E) : Expr(PredefinedExprClass, FnTy, VK_LValue, OK_Ordinary) { PredefinedExprBits.Kind = IK; assert((getIdentKind() == IK) && @@ -531,7 +531,7 @@ PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FnTy, IdentKind IK, "Constructor only valid with UniqueStableNameExpr"); PredefinedExprBits.HasFunctionName = false; PredefinedExprBits.Loc = L; - setExpr(Info); + setExpr(E); setDependence(computeDependence(this)); } @@ -3398,6 +3398,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ParenExprClass: case ArraySubscriptExprClass: case OMPArraySectionExprClass: + case OMPArrayShapingExprClass: + case OMPIteratorExprClass: case MemberExprClass: case ConditionalOperatorClass: case BinaryConditionalOperatorClass: @@ -4569,3 +4571,165 @@ RecoveryExpr *RecoveryExpr::CreateEmpty(ASTContext &Ctx, unsigned NumSubExprs) { alignof(RecoveryExpr)); return new (Mem) RecoveryExpr(EmptyShell()); } + +void OMPArrayShapingExpr::setDimensions(ArrayRef Dims) { + assert( + NumDims == Dims.size() && + "Preallocated number of dimensions is different from the provided one."); + llvm::copy(Dims, getTrailingObjects()); +} + +void OMPArrayShapingExpr::setBracketsRanges(ArrayRef BR) { + assert( + NumDims == BR.size() && + "Preallocated number of dimensions is different from the provided one."); + llvm::copy(BR, getTrailingObjects()); +} + +OMPArrayShapingExpr::OMPArrayShapingExpr(QualType ExprTy, Expr *Op, + SourceLocation L, SourceLocation R, + ArrayRef Dims) + : Expr(OMPArrayShapingExprClass, ExprTy, VK_LValue, OK_Ordinary), LPLoc(L), + RPLoc(R), NumDims(Dims.size()) { + setBase(Op); + setDimensions(Dims); + setDependence(computeDependence(this)); +} + +OMPArrayShapingExpr * +OMPArrayShapingExpr::Create(const ASTContext &Context, QualType T, Expr *Op, + SourceLocation L, SourceLocation R, + ArrayRef Dims, + ArrayRef BracketRanges) { + assert(Dims.size() == BracketRanges.size() && + "Different number of dimensions and brackets ranges."); + void *Mem = Context.Allocate( + totalSizeToAlloc(Dims.size() + 1, Dims.size()), + alignof(OMPArrayShapingExpr)); + auto *E = new (Mem) OMPArrayShapingExpr(T, Op, L, R, Dims); + E->setBracketsRanges(BracketRanges); + return E; +} + +OMPArrayShapingExpr *OMPArrayShapingExpr::CreateEmpty(const ASTContext &Context, + unsigned NumDims) { + void *Mem = Context.Allocate( + totalSizeToAlloc(NumDims + 1, NumDims), + alignof(OMPArrayShapingExpr)); + return new (Mem) OMPArrayShapingExpr(EmptyShell(), NumDims); +} + +void OMPIteratorExpr::setIteratorDeclaration(unsigned I, Decl *D) { + assert(I < NumIterators && + "Idx is greater or equal the number of iterators definitions."); + getTrailingObjects()[I] = D; +} + +void OMPIteratorExpr::setAssignmentLoc(unsigned I, SourceLocation Loc) { + assert(I < NumIterators && + "Idx is greater or equal the number of iterators definitions."); + getTrailingObjects< + SourceLocation>()[I * static_cast(RangeLocOffset::Total) + + static_cast(RangeLocOffset::AssignLoc)] = Loc; +} + +void OMPIteratorExpr::setIteratorRange(unsigned I, Expr *Begin, + SourceLocation ColonLoc, Expr *End, + SourceLocation SecondColonLoc, + Expr *Step) { + assert(I < NumIterators && + "Idx is greater or equal the number of iterators definitions."); + getTrailingObjects()[I * static_cast(RangeExprOffset::Total) + + static_cast(RangeExprOffset::Begin)] = + Begin; + getTrailingObjects()[I * static_cast(RangeExprOffset::Total) + + static_cast(RangeExprOffset::End)] = End; + getTrailingObjects()[I * static_cast(RangeExprOffset::Total) + + static_cast(RangeExprOffset::Step)] = Step; + getTrailingObjects< + SourceLocation>()[I * static_cast(RangeLocOffset::Total) + + static_cast(RangeLocOffset::FirstColonLoc)] = + ColonLoc; + getTrailingObjects< + SourceLocation>()[I * static_cast(RangeLocOffset::Total) + + static_cast(RangeLocOffset::SecondColonLoc)] = + SecondColonLoc; +} + +Decl *OMPIteratorExpr::getIteratorDecl(unsigned I) { + return getTrailingObjects()[I]; +} + +OMPIteratorExpr::IteratorRange OMPIteratorExpr::getIteratorRange(unsigned I) { + IteratorRange Res; + Res.Begin = + getTrailingObjects()[I * static_cast( + RangeExprOffset::Total) + + static_cast(RangeExprOffset::Begin)]; + Res.End = + getTrailingObjects()[I * static_cast( + RangeExprOffset::Total) + + static_cast(RangeExprOffset::End)]; + Res.Step = + getTrailingObjects()[I * static_cast( + RangeExprOffset::Total) + + static_cast(RangeExprOffset::Step)]; + return Res; +} + +SourceLocation OMPIteratorExpr::getAssignLoc(unsigned I) const { + return getTrailingObjects< + SourceLocation>()[I * static_cast(RangeLocOffset::Total) + + static_cast(RangeLocOffset::AssignLoc)]; +} + +SourceLocation OMPIteratorExpr::getColonLoc(unsigned I) const { + return getTrailingObjects< + SourceLocation>()[I * static_cast(RangeLocOffset::Total) + + static_cast(RangeLocOffset::FirstColonLoc)]; +} + +SourceLocation OMPIteratorExpr::getSecondColonLoc(unsigned I) const { + return getTrailingObjects< + SourceLocation>()[I * static_cast(RangeLocOffset::Total) + + static_cast(RangeLocOffset::SecondColonLoc)]; +} + +OMPIteratorExpr::OMPIteratorExpr( + QualType ExprTy, SourceLocation IteratorKwLoc, SourceLocation L, + SourceLocation R, ArrayRef Data) + : Expr(OMPIteratorExprClass, ExprTy, VK_LValue, OK_Ordinary), + IteratorKwLoc(IteratorKwLoc), LPLoc(L), RPLoc(R), + NumIterators(Data.size()) { + for (unsigned I = 0, E = Data.size(); I < E; ++I) { + const IteratorDefinition &D = Data[I]; + setIteratorDeclaration(I, D.IteratorDecl); + setAssignmentLoc(I, D.AssignmentLoc); + setIteratorRange(I, D.Range.Begin, D.ColonLoc, D.Range.End, + D.SecondColonLoc, D.Range.Step); + } + setDependence(computeDependence(this)); +} + +OMPIteratorExpr * +OMPIteratorExpr::Create(const ASTContext &Context, QualType T, + SourceLocation IteratorKwLoc, SourceLocation L, + SourceLocation R, + ArrayRef Data) { + void *Mem = Context.Allocate( + totalSizeToAlloc( + Data.size(), Data.size() * static_cast(RangeExprOffset::Total), + Data.size() * static_cast(RangeLocOffset::Total)), + alignof(OMPIteratorExpr)); + return new (Mem) OMPIteratorExpr(T, IteratorKwLoc, L, R, Data); +} + +OMPIteratorExpr *OMPIteratorExpr::CreateEmpty(const ASTContext &Context, + unsigned NumIterators) { + void *Mem = Context.Allocate( + totalSizeToAlloc( + NumIterators, NumIterators * static_cast(RangeExprOffset::Total), + NumIterators * static_cast(RangeLocOffset::Total)), + alignof(OMPIteratorExpr)); + return new (Mem) OMPIteratorExpr(EmptyShell(), NumIterators); +} diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 58e70347292c7..8587a476a5d90 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -140,6 +140,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::MSPropertyRefExprClass: case Expr::MSPropertySubscriptExprClass: case Expr::OMPArraySectionExprClass: + case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 06f4885e47d6c..c6e1cc7b67df3 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8677,6 +8677,10 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This, APValue &Result, const InitListExpr *ILE, QualType AllocType); +static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This, + APValue &Result, + const CXXConstructExpr *CCE, + QualType AllocType); bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { if (!Info.getLangOpts().CPlusPlus2a) @@ -8726,6 +8730,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { const Expr *Init = E->getInitializer(); const InitListExpr *ResizedArrayILE = nullptr; + const CXXConstructExpr *ResizedArrayCCE = nullptr; QualType AllocType = E->getAllocatedType(); if (Optional ArraySize = E->getArraySize()) { @@ -8769,7 +8774,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { // -- the new-initializer is a braced-init-list and the number of // array elements for which initializers are provided [...] // exceeds the number of elements to initialize - if (Init) { + if (Init && !isa(Init)) { auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType()); assert(CAT && "unexpected type for array initializer"); @@ -8792,6 +8797,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { // special handling for this case when we initialize. if (InitBound != AllocBound) ResizedArrayILE = cast(Init); + } else if (Init) { + ResizedArrayCCE = cast(Init); } AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr, @@ -8856,6 +8863,10 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { if (!EvaluateArrayNewInitList(Info, Result, *Val, ResizedArrayILE, AllocType)) return false; + } else if (ResizedArrayCCE) { + if (!EvaluateArrayNewConstructExpr(Info, Result, *Val, ResizedArrayCCE, + AllocType)) + return false; } else if (Init) { if (!EvaluateInPlace(*Val, Info, Result, Init)) return false; @@ -9683,6 +9694,16 @@ static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This, .VisitInitListExpr(ILE, AllocType); } +static bool EvaluateArrayNewConstructExpr(EvalInfo &Info, LValue &This, + APValue &Result, + const CXXConstructExpr *CCE, + QualType AllocType) { + assert(CCE->isRValue() && CCE->getType()->isArrayType() && + "not an array rvalue"); + return ArrayExprEvaluator(Info, This, Result) + .VisitCXXConstructExpr(CCE, This, &Result, AllocType); +} + // Return true iff the given array filler may depend on the element index. static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) { // For now, just whitelist non-class value-initialization and initialization @@ -14159,6 +14180,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::StringLiteralClass: case Expr::ArraySubscriptExprClass: case Expr::OMPArraySectionExprClass: + case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: case Expr::MemberExprClass: case Expr::CompoundAssignOperatorClass: case Expr::CompoundLiteralExprClass: diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 823c085c4aea8..0495a44a38370 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3714,6 +3714,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::TypoExprClass: // This should no longer exist in the AST by now. case Expr::RecoveryExprClass: case Expr::OMPArraySectionExprClass: + case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: case Expr::CXXInheritedCtorInitExprClass: llvm_unreachable("unexpected statement kind"); diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 4c32093bc9dc9..0b3c9b738f9c4 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -2940,11 +2940,17 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers, void MicrosoftCXXNameMangler::mangleType(const PipeType *T, Qualifiers, SourceRange Range) { - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this OpenCL pipe type yet"); - Diags.Report(Range.getBegin(), DiagID) - << Range; + QualType ElementType = T->getElementType(); + + llvm::SmallString<64> TemplateMangling; + llvm::raw_svector_ostream Stream(TemplateMangling); + MicrosoftCXXNameMangler Extra(Context, Stream); + Stream << "?$"; + Extra.mangleSourceName("ocl_pipe"); + Extra.mangleType(ElementType, Range, QMM_Escape); + Extra.mangleIntegerLiteral(llvm::APSInt::get(T->isReadOnly()), true); + + mangleArtificialTagType(TTK_Struct, TemplateMangling, {"__clang"}); } void MicrosoftMangleContextImpl::mangleCXXName(GlobalDecl GD, diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index ae6ff04f5126d..3bb3605ea9361 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -483,6 +483,8 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::PseudoObject: case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: break; } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index fc7912d6fdcac..a205a1bca1b98 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -24,6 +24,8 @@ #include using namespace clang; +using namespace llvm; +using namespace omp; OMPClause::child_range OMPClause::children() { switch (getClauseKind()) { @@ -898,16 +900,19 @@ OMPDepobjClause *OMPDepobjClause::CreateEmpty(const ASTContext &C) { OMPDependClause * OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, - OpenMPDependClauseKind DepKind, SourceLocation DepLoc, - SourceLocation ColonLoc, ArrayRef VL, - unsigned NumLoops) { - void *Mem = C.Allocate(totalSizeToAlloc(VL.size() + NumLoops)); + Expr *DepModifier, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef VL, unsigned NumLoops) { + void *Mem = C.Allocate( + totalSizeToAlloc(VL.size() + /*depend-modifier*/ 1 + NumLoops), + alignof(OMPDependClause)); OMPDependClause *Clause = new (Mem) OMPDependClause(StartLoc, LParenLoc, EndLoc, VL.size(), NumLoops); Clause->setVarRefs(VL); Clause->setDependencyKind(DepKind); Clause->setDependencyLoc(DepLoc); Clause->setColonLoc(ColonLoc); + Clause->setModifier(DepModifier); for (unsigned I = 0 ; I < NumLoops; ++I) Clause->setLoopData(I, nullptr); return Clause; @@ -915,7 +920,9 @@ OMPDependClause::Create(const ASTContext &C, SourceLocation StartLoc, OMPDependClause *OMPDependClause::CreateEmpty(const ASTContext &C, unsigned N, unsigned NumLoops) { - void *Mem = C.Allocate(totalSizeToAlloc(N + NumLoops)); + void *Mem = + C.Allocate(totalSizeToAlloc(N + /*depend-modifier*/ 1 + NumLoops), + alignof(OMPDependClause)); return new (Mem) OMPDependClause(N, NumLoops); } @@ -925,7 +932,7 @@ void OMPDependClause::setLoopData(unsigned NumLoop, Expr *Cnt) { NumLoop < NumLoops && "Expected sink or source depend + loop index must be less number of " "loops."); - auto It = std::next(getVarRefs().end(), NumLoop); + auto *It = std::next(getVarRefs().end(), NumLoop + 1); *It = Cnt; } @@ -935,7 +942,7 @@ Expr *OMPDependClause::getLoopData(unsigned NumLoop) { NumLoop < NumLoops && "Expected sink or source depend + loop index must be less number of " "loops."); - auto It = std::next(getVarRefs().end(), NumLoop); + auto *It = std::next(getVarRefs().end(), NumLoop + 1); return *It; } @@ -945,10 +952,15 @@ const Expr *OMPDependClause::getLoopData(unsigned NumLoop) const { NumLoop < NumLoops && "Expected sink or source depend + loop index must be less number of " "loops."); - auto It = std::next(getVarRefs().end(), NumLoop); + const auto *It = std::next(getVarRefs().end(), NumLoop + 1); return *It; } +void OMPDependClause::setModifier(Expr *DepModifier) { + *getVarRefs().end() = DepModifier; +} +Expr *OMPDependClause::getModifier() { return *getVarRefs().end(); } + unsigned OMPClauseMappableExprCommon::getComponentsTotalNumber( MappableExprComponentListsRef ComponentLists) { unsigned TotalNum = 0u; @@ -1296,7 +1308,7 @@ OMPExclusiveClause *OMPExclusiveClause::CreateEmpty(const ASTContext &C, void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) { OS << "if("; - if (Node->getNameModifier() != llvm::omp::OMPD_unknown) + if (Node->getNameModifier() != OMPD_unknown) OS << getOpenMPDirectiveName(Node->getNameModifier()) << ": "; Node->getCondition()->printPretty(OS, nullptr, Policy, 0); OS << ")"; @@ -1725,6 +1737,10 @@ void OMPClausePrinter::VisitOMPDepobjClause(OMPDepobjClause *Node) { void OMPClausePrinter::VisitOMPDependClause(OMPDependClause *Node) { OS << "depend("; + if (Expr *DepModifier = Node->getModifier()) { + DepModifier->printPretty(OS, nullptr, Policy); + OS << ", "; + } OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Node->getDependencyKind()); if (!Node->varlist_empty()) { @@ -1738,7 +1754,7 @@ void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) { if (!Node->varlist_empty()) { OS << "map("; if (Node->getMapType() != OMPC_MAP_unknown) { - for (unsigned I = 0; I < OMPMapClause::NumberOfModifiers; ++I) { + for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) { if (Node->getMapTypeModifier(I) != OMPC_MAP_MODIFIER_unknown) { OS << getOpenMPSimpleClauseTypeName(OMPC_map, Node->getMapTypeModifier(I)); @@ -1866,25 +1882,28 @@ void OMPClausePrinter::VisitOMPExclusiveClause(OMPExclusiveClause *Node) { } } -void OMPTraitInfo::getAsVariantMatchInfo( - ASTContext &ASTCtx, llvm::omp::VariantMatchInfo &VMI) const { +void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx, + VariantMatchInfo &VMI, + bool DeviceSetOnly) const { for (const OMPTraitSet &Set : Sets) { + if (DeviceSetOnly && Set.Kind != TraitSet::device) + continue; for (const OMPTraitSelector &Selector : Set.Selectors) { // User conditions are special as we evaluate the condition here. - if (Selector.Kind == llvm::omp::TraitSelector::user_condition) { + if (Selector.Kind == TraitSelector::user_condition) { assert(Selector.ScoreOrCondition && "Ill-formed user condition, expected condition expression!"); assert(Selector.Properties.size() == 1 && Selector.Properties.front().Kind == - llvm::omp::TraitProperty::user_condition_unknown && + TraitProperty::user_condition_unknown && "Ill-formed user condition, expected unknown trait property!"); llvm::APInt CondVal = Selector.ScoreOrCondition->EvaluateKnownConstInt(ASTCtx); VMI.addTrait(CondVal.isNullValue() - ? llvm::omp::TraitProperty::user_condition_false - : llvm::omp::TraitProperty::user_condition_true); + ? TraitProperty::user_condition_false + : TraitProperty::user_condition_true); continue; } @@ -1897,13 +1916,13 @@ void OMPTraitInfo::getAsVariantMatchInfo( for (const OMPTraitProperty &Property : Selector.Properties) VMI.addTrait(Set.Kind, Property.Kind, ScorePtr); - if (Set.Kind != llvm::omp::TraitSet::construct) + if (Set.Kind != TraitSet::construct) continue; // TODO: This might not hold once we implement SIMD properly. assert(Selector.Properties.size() == 1 && Selector.Properties.front().Kind == - llvm::omp::getOpenMPContextTraitPropertyForSelector( + getOpenMPContextTraitPropertyForSelector( Selector.Kind) && "Ill-formed construct selector!"); @@ -1915,29 +1934,29 @@ void OMPTraitInfo::getAsVariantMatchInfo( void OMPTraitInfo::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { bool FirstSet = true; - for (const OMPTraitInfo::OMPTraitSet &Set : Sets) { + for (const OMPTraitSet &Set : Sets) { if (!FirstSet) OS << ", "; FirstSet = false; - OS << llvm::omp::getOpenMPContextTraitSetName(Set.Kind) << "={"; + OS << getOpenMPContextTraitSetName(Set.Kind) << "={"; bool FirstSelector = true; - for (const OMPTraitInfo::OMPTraitSelector &Selector : Set.Selectors) { + for (const OMPTraitSelector &Selector : Set.Selectors) { if (!FirstSelector) OS << ", "; FirstSelector = false; - OS << llvm::omp::getOpenMPContextTraitSelectorName(Selector.Kind); + OS << getOpenMPContextTraitSelectorName(Selector.Kind); bool AllowsTraitScore = false; bool RequiresProperty = false; - llvm::omp::isValidTraitSelectorForTraitSet( + isValidTraitSelectorForTraitSet( Selector.Kind, Set.Kind, AllowsTraitScore, RequiresProperty); if (!RequiresProperty) continue; OS << "("; - if (Selector.Kind == llvm::omp::TraitSelector::user_condition) { + if (Selector.Kind == TraitSelector::user_condition) { Selector.ScoreOrCondition->printPretty(OS, nullptr, Policy); } else { @@ -1948,12 +1967,11 @@ void OMPTraitInfo::print(llvm::raw_ostream &OS, } bool FirstProperty = true; - for (const OMPTraitInfo::OMPTraitProperty &Property : - Selector.Properties) { + for (const OMPTraitProperty &Property : Selector.Properties) { if (!FirstProperty) OS << ", "; FirstProperty = false; - OS << llvm::omp::getOpenMPContextTraitPropertyName(Property.Kind); + OS << getOpenMPContextTraitPropertyName(Property.Kind); } } OS << ")"; @@ -1962,6 +1980,63 @@ void OMPTraitInfo::print(llvm::raw_ostream &OS, } } +std::string OMPTraitInfo::getMangledName() const { + std::string MangledName; + llvm::raw_string_ostream OS(MangledName); + for (const OMPTraitSet &Set : Sets) { + OS << '.' << 'S' << unsigned(Set.Kind); + for (const OMPTraitSelector &Selector : Set.Selectors) { + + bool AllowsTraitScore = false; + bool RequiresProperty = false; + isValidTraitSelectorForTraitSet( + Selector.Kind, Set.Kind, AllowsTraitScore, RequiresProperty); + OS << '.' << 's' << unsigned(Selector.Kind); + + if (!RequiresProperty || + Selector.Kind == TraitSelector::user_condition) + continue; + + for (const OMPTraitProperty &Property : Selector.Properties) + OS << '.' << 'P' + << getOpenMPContextTraitPropertyName(Property.Kind); + } + } + return OS.str(); +} + +OMPTraitInfo::OMPTraitInfo(StringRef MangledName) { + unsigned long U; + do { + if (!MangledName.consume_front(".S")) + break; + if (MangledName.consumeInteger(10, U)) + break; + Sets.push_back(OMPTraitSet()); + OMPTraitSet &Set = Sets.back(); + Set.Kind = TraitSet(U); + do { + if (!MangledName.consume_front(".s")) + break; + if (MangledName.consumeInteger(10, U)) + break; + Set.Selectors.push_back(OMPTraitSelector()); + OMPTraitSelector &Selector = Set.Selectors.back(); + Selector.Kind = TraitSelector(U); + do { + if (!MangledName.consume_front(".P")) + break; + Selector.Properties.push_back(OMPTraitProperty()); + OMPTraitProperty &Property = Selector.Properties.back(); + std::pair PropRestPair = MangledName.split('.'); + Property.Kind = + getOpenMPContextTraitPropertyKind(Set.Kind, PropRestPair.first); + MangledName = PropRestPair.second; + } while (true); + } while (true); + } while (true); +} + llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI) { LangOptions LO; diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index bae60d4644078..d13ff0a02d171 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -11,10 +11,11 @@ // //===----------------------------------------------------------------------===// +#include "FormatStringParsing.h" #include "clang/AST/FormatString.h" #include "clang/AST/OSLog.h" -#include "FormatStringParsing.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/Support/Regex.h" using clang::analyze_format_string::ArgType; using clang::analyze_format_string::FormatStringHandler; diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 932edb75bd584..cd54b61ca3d89 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -3226,7 +3226,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, if (D->hasExternalLexicalStorage() && !D->getDefinition()) getExternalSource()->CompleteType(const_cast(D)); D = D->getDefinition(); - assert(D && D->isThisDeclarationADefinition() && "Invalid interface decl!"); + assert(D && !D->isInvalidDecl() && D->isThisDeclarationADefinition() && + "Invalid interface decl!"); // Look up this layout, if already laid out, return what we have. const ObjCContainerDecl *Key = diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 80fdc09a8a6cf..6537ca98667e3 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1350,6 +1350,37 @@ void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) { OS << "]"; } +void StmtPrinter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *Node) { + OS << "("; + for (Expr *E : Node->getDimensions()) { + OS << "["; + PrintExpr(E); + OS << "]"; + } + OS << ")"; + PrintExpr(Node->getBase()); +} + +void StmtPrinter::VisitOMPIteratorExpr(OMPIteratorExpr *Node) { + OS << "iterator("; + for (unsigned I = 0, E = Node->numOfIterators(); I < E; ++I) { + auto *VD = cast(Node->getIteratorDecl(I)); + VD->getType().print(OS, Policy); + const OMPIteratorExpr::IteratorRange Range = Node->getIteratorRange(I); + OS << " " << VD->getName() << " = "; + PrintExpr(Range.Begin); + OS << ":"; + PrintExpr(Range.End); + if (Range.Step) { + OS << ":"; + PrintExpr(Range.Step); + } + if (I < E - 1) + OS << ", "; + } + OS << ")"; +} + void StmtPrinter::PrintCallArgs(CallExpr *Call) { for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { if (isa(Call->getArg(i))) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 5e87eb3e237c3..fec12ac98b4ea 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1194,6 +1194,16 @@ void StmtProfiler::VisitOMPArraySectionExpr(const OMPArraySectionExpr *S) { VisitExpr(S); } +void StmtProfiler::VisitOMPArrayShapingExpr(const OMPArrayShapingExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitOMPIteratorExpr(const OMPIteratorExpr *S) { + VisitExpr(S); + for (unsigned I = 0, E = S->numOfIterators(); I < E; ++I) + VisitDecl(S->getIteratorDecl(I)); +} + void StmtProfiler::VisitCallExpr(const CallExpr *S) { VisitExpr(S); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 6a6d8692228af..dc0dd92f09df6 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1086,6 +1086,23 @@ void TextNodeDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) { OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no"); } +void TextNodeDumper::VisitOMPIteratorExpr(const OMPIteratorExpr *Node) { + OS << " "; + for (unsigned I = 0, E = Node->numOfIterators(); I < E; ++I) { + Visit(Node->getIteratorDecl(I)); + OS << " = "; + const OMPIteratorExpr::IteratorRange Range = Node->getIteratorRange(I); + OS << " begin "; + Visit(Range.Begin); + OS << " end "; + Visit(Range.End); + if (Range.Step) { + OS << " step "; + Visit(Range.Step); + } + } +} + void TextNodeDumper::VisitRValueReferenceType(const ReferenceType *T) { if (T->isSpelledAsLValue()) OS << " written as lvalue reference"; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 69c942e46f729..3428437c31462 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2249,6 +2249,9 @@ bool QualType::isTrivialType(const ASTContext &Context) const { if ((*this)->isArrayType()) return Context.getBaseElementType(*this).isTrivialType(Context); + if ((*this)->isSizelessBuiltinType()) + return true; + // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if ((*this)->isIncompleteType()) @@ -2303,6 +2306,9 @@ bool QualType::isTriviallyCopyableType(const ASTContext &Context) const { if (CanonicalType->isDependentType()) return false; + if (CanonicalType->isSizelessBuiltinType()) + return true; + // Return false for incomplete types after skipping any incomplete array types // which are expressly allowed by the standard and thus our API. if (CanonicalType->isIncompleteType()) @@ -2496,6 +2502,9 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const { const Type *BaseTy = ty->getBaseElementTypeUnsafe(); assert(BaseTy && "NULL element type"); + if (BaseTy->isSizelessBuiltinType()) + return true; + // Return false for incomplete types after skipping any incomplete array // types which are expressly allowed by the standard and thus our API. if (BaseTy->isIncompleteType()) @@ -2899,6 +2908,10 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "reserve_id_t"; case OMPArraySection: return ""; + case OMPArrayShaping: + return ""; + case OMPIterator: + return ""; #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case Id: \ return #ExtType; @@ -3905,6 +3918,8 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case BuiltinType::BuiltinFn: case BuiltinType::NullPtr: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: return false; } llvm_unreachable("unknown builtin type"); @@ -4084,6 +4099,20 @@ bool Type::isCARCBridgableType() const { return Pointee->isVoidType() || Pointee->isRecordType(); } +/// Check if the specified type is the CUDA device builtin surface type. +bool Type::isCUDADeviceBuiltinSurfaceType() const { + if (const auto *RT = getAs()) + return RT->getDecl()->hasAttr(); + return false; +} + +/// Check if the specified type is the CUDA device builtin texture type. +bool Type::isCUDADeviceBuiltinTextureType() const { + if (const auto *RT = getAs()) + return RT->getDecl()->hasAttr(); + return false; +} + bool Type::hasSizedVLAType() const { if (!isVariablyModifiedType()) return false; diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 665a86f2c1432..50391dba2a05a 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -404,6 +404,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { #include "clang/Basic/AArch64SVEACLETypes.def" case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: return TST_unspecified; } diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 28244fea55b24..8df93e8c51de8 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1739,13 +1739,13 @@ static void printTo(raw_ostream &OS, ArrayRef Args, OS << ArgString; - NeedSpace = (!ArgString.empty() && ArgString.back() == '>'); + // If the last character of our string is '>', add another space to + // keep the two '>''s separate tokens. + NeedSpace = Policy.SplitTemplateClosers && !ArgString.empty() && + ArgString.back() == '>'; FirstArg = false; } - // If the last character of our string is '>', add another space to - // keep the two '>''s separate tokens. We don't *have* to do this in - // C++0x, but it's still good hygiene. if (NeedSpace) OS << ' '; diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp index 00bc854a88049..9f45a8efe546f 100644 --- a/clang/lib/Analysis/RetainSummaryManager.cpp +++ b/clang/lib/Analysis/RetainSummaryManager.cpp @@ -146,7 +146,9 @@ static bool isSubclass(const Decl *D, } static bool isOSObjectSubclass(const Decl *D) { - return D && isSubclass(D, "OSMetaClassBase"); + // OSSymbols are particular OSObjects that are allocated globally + // and therefore aren't really refcounted, so we ignore them. + return D && isSubclass(D, "OSMetaClassBase") && !isSubclass(D, "OSSymbol"); } static bool isOSObjectDynamicCast(StringRef S) { diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 252083f377d94..e0ff23df5ab4b 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -2139,12 +2139,14 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) { // handle constructors that involve temporaries if (auto *EWC = dyn_cast(E)) - E = EWC->getSubExpr(); - if (auto *ICE = dyn_cast(E)) - if (ICE->getCastKind() == CK_NoOp) - E = ICE->getSubExpr(); + E = EWC->getSubExpr()->IgnoreParens(); + if (auto *CE = dyn_cast(E)) + if (CE->getCastKind() == CK_NoOp || + CE->getCastKind() == CK_ConstructorConversion || + CE->getCastKind() == CK_UserDefinedConversion) + E = CE->getSubExpr()->IgnoreParens(); if (auto *BTE = dyn_cast(E)) - E = BTE->getSubExpr(); + E = BTE->getSubExpr()->IgnoreParens(); if (const auto *CE = dyn_cast(E)) { const auto *CtorD = dyn_cast_or_null(CE->getConstructor()); diff --git a/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp b/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp index 77de3630ae7ec..32fba9c93752c 100644 --- a/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp +++ b/clang/lib/Analysis/plugins/CheckerOptionHandling/CheckerOptionHandling.cpp @@ -21,7 +21,7 @@ void registerMyChecker(CheckerManager &Mgr) { << '\n'; } -bool shouldRegisterMyChecker(const LangOptions &LO) { return true; } +bool shouldRegisterMyChecker(const CheckerManager &mgr) { return true; } } // end anonymous namespace diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index a860c9dba2ef8..ff6dbf870fcf4 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -85,12 +85,12 @@ static SmallString<64> normalizeName(const IdentifierInfo *Name, StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed); StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed); - // Ensure that in the case of C++11 attributes, we look for '::foo' if it is - // unscoped. SmallString<64> FullName = ScopeName; - if (Scope || SyntaxUsed == AttributeCommonInfo::AS_CXX11 || - SyntaxUsed == AttributeCommonInfo::AS_C2x) + if (!ScopeName.empty()) { + assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 || + SyntaxUsed == AttributeCommonInfo::AS_C2x); FullName += "::"; + } FullName += AttrName; return FullName; diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index e06d120c58bfc..74eb5473b71d2 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -362,7 +362,7 @@ CudaVersion MaxVersionForCudaArch(CudaArch A) { } } -static CudaVersion ToCudaVersion(llvm::VersionTuple Version) { +CudaVersion ToCudaVersion(llvm::VersionTuple Version) { int IVer = Version.getMajor() * 10 + Version.getMinor().getValueOr(0); switch(IVer) { diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index dd8f11101107a..5fd7d304f8f42 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -659,7 +659,7 @@ void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, VisitModule({M, nullptr}); } -ASTSourceDescriptor::ASTSourceDescriptor(const Module &M) +ASTSourceDescriptor::ASTSourceDescriptor(Module &M) : Signature(M.Signature), ClangModule(&M) { if (M.Directory) Path = M.Directory->getName(); diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index e8bf41dc07be2..7a7c66c8e5872 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -1025,6 +1025,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; } break; + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_unknown: @@ -1288,6 +1290,8 @@ void clang::getOpenMPCaptureRegions( case OMPD_end_declare_target: case OMPD_requires: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 2330339bedfb2..2f1e044bb106d 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -133,6 +133,8 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { // Default to an unknown platform name. PlatformName = "unknown"; PlatformMinVersion = VersionTuple(); + + MaxOpenCLWorkGroupSize = 1024; } // Out of line virtual dtor for TargetInfo. diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 74bb6900b19e3..8ceb7f2b515e4 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "AArch64.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ArrayRef.h" @@ -121,15 +122,15 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, return false; BPI.SignReturnAddr = - llvm::StringSwitch(PBP.Scope) - .Case("non-leaf", CodeGenOptions::SignReturnAddressScope::NonLeaf) - .Case("all", CodeGenOptions::SignReturnAddressScope::All) - .Default(CodeGenOptions::SignReturnAddressScope::None); + llvm::StringSwitch(PBP.Scope) + .Case("non-leaf", LangOptions::SignReturnAddressScopeKind::NonLeaf) + .Case("all", LangOptions::SignReturnAddressScopeKind::All) + .Default(LangOptions::SignReturnAddressScopeKind::None); if (PBP.Key == "a_key") - BPI.SignKey = CodeGenOptions::SignReturnAddressKeyValue::AKey; + BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey; else - BPI.SignKey = CodeGenOptions::SignReturnAddressKeyValue::BKey; + BPI.SignKey = LangOptions::SignReturnAddressKeyKind::BKey; BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; return true; @@ -151,6 +152,7 @@ void AArch64TargetInfo::fillValidCPUList( void AArch64TargetInfo::getTargetDefinesARMV81A(const LangOptions &Opts, MacroBuilder &Builder) const { + // FIXME: Armv8.1 makes __ARM_FEATURE_CRC32 mandatory. Handle it here. Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); } @@ -171,17 +173,26 @@ void AArch64TargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts, void AArch64TargetInfo::getTargetDefinesARMV84A(const LangOptions &Opts, MacroBuilder &Builder) const { // Also include the Armv8.3 defines - // FIXME: Armv8.4 makes some extensions mandatory. Handle them here. + // FIXME: Armv8.4 makes __ARM_FEATURE_ATOMICS, defined in GCC, mandatory. + // Add and handle it here. getTargetDefinesARMV83A(Opts, Builder); } void AArch64TargetInfo::getTargetDefinesARMV85A(const LangOptions &Opts, MacroBuilder &Builder) const { // Also include the Armv8.4 defines - // FIXME: Armv8.5 makes some extensions mandatory. Handle them here. getTargetDefinesARMV84A(Opts, Builder); } +void AArch64TargetInfo::getTargetDefinesARMV86A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the Armv8.5 defines + // FIXME: Armv8.6 makes the following extensions mandatory: + // - __ARM_FEATURE_BF16 + // - __ARM_FEATURE_MATMUL_INT8 + // Handle them here. + getTargetDefinesARMV85A(Opts, Builder); +} void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -272,6 +283,27 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if ((FPU & NeonMode) && HasFP16FML) Builder.defineMacro("__ARM_FEATURE_FP16FML", "1"); + if (Opts.hasSignReturnAddress()) { + // Bitmask: + // 0: Protection using the A key + // 1: Protection using the B key + // 2: Protection including leaf functions + unsigned Value = 0; + + if (Opts.isSignReturnAddressWithAKey()) + Value |= (1 << 0); + else + Value |= (1 << 1); + + if (Opts.isSignReturnAddressScopeAll()) + Value |= (1 << 2); + + Builder.defineMacro("__ARM_FEATURE_PAC_DEFAULT", std::to_string(Value)); + } + + if (Opts.BranchTargetEnforcement) + Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1"); + switch (ArchKind) { default: break; @@ -290,6 +322,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::AArch64::ArchKind::ARMV8_5A: getTargetDefinesARMV85A(Opts, Builder); break; + case llvm::AArch64::ArchKind::ARMV8_6A: + getTargetDefinesARMV86A(Opts, Builder); + break; } // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. @@ -344,6 +379,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, ArchKind = llvm::AArch64::ArchKind::ARMV8_4A; if (Feature == "+v8.5a") ArchKind = llvm::AArch64::ArchKind::ARMV8_5A; + if (Feature == "+v8.6a") + ArchKind = llvm::AArch64::ArchKind::ARMV8_6A; if (Feature == "+fullfp16") HasFullFP16 = true; if (Feature == "+dotprod") diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 41970e5d716e7..bc73d195b7d4f 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -70,6 +70,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { MacroBuilder &Builder) const; void getTargetDefinesARMV85A(const LangOptions &Opts, MacroBuilder &Builder) const; + void getTargetDefinesARMV86A(const LangOptions &Opts, + MacroBuilder &Builder) const; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index 8017bc3fd5c4f..8e948f22a7366 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -133,7 +133,36 @@ const char *const AMDGPUTargetInfo::GCCRegNames[] = { "s113", "s114", "s115", "s116", "s117", "s118", "s119", "s120", "s121", "s122", "s123", "s124", "s125", "s126", "s127", "exec", "vcc", "scc", "m0", "flat_scratch", "exec_lo", "exec_hi", "vcc_lo", "vcc_hi", - "flat_scratch_lo", "flat_scratch_hi" + "flat_scratch_lo", "flat_scratch_hi", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", + "a9", "a10", "a11", "a12", "a13", "a14", "a15", "a16", "a17", + "a18", "a19", "a20", "a21", "a22", "a23", "a24", "a25", "a26", + "a27", "a28", "a29", "a30", "a31", "a32", "a33", "a34", "a35", + "a36", "a37", "a38", "a39", "a40", "a41", "a42", "a43", "a44", + "a45", "a46", "a47", "a48", "a49", "a50", "a51", "a52", "a53", + "a54", "a55", "a56", "a57", "a58", "a59", "a60", "a61", "a62", + "a63", "a64", "a65", "a66", "a67", "a68", "a69", "a70", "a71", + "a72", "a73", "a74", "a75", "a76", "a77", "a78", "a79", "a80", + "a81", "a82", "a83", "a84", "a85", "a86", "a87", "a88", "a89", + "a90", "a91", "a92", "a93", "a94", "a95", "a96", "a97", "a98", + "a99", "a100", "a101", "a102", "a103", "a104", "a105", "a106", "a107", + "a108", "a109", "a110", "a111", "a112", "a113", "a114", "a115", "a116", + "a117", "a118", "a119", "a120", "a121", "a122", "a123", "a124", "a125", + "a126", "a127", "a128", "a129", "a130", "a131", "a132", "a133", "a134", + "a135", "a136", "a137", "a138", "a139", "a140", "a141", "a142", "a143", + "a144", "a145", "a146", "a147", "a148", "a149", "a150", "a151", "a152", + "a153", "a154", "a155", "a156", "a157", "a158", "a159", "a160", "a161", + "a162", "a163", "a164", "a165", "a166", "a167", "a168", "a169", "a170", + "a171", "a172", "a173", "a174", "a175", "a176", "a177", "a178", "a179", + "a180", "a181", "a182", "a183", "a184", "a185", "a186", "a187", "a188", + "a189", "a190", "a191", "a192", "a193", "a194", "a195", "a196", "a197", + "a198", "a199", "a200", "a201", "a202", "a203", "a204", "a205", "a206", + "a207", "a208", "a209", "a210", "a211", "a212", "a213", "a214", "a215", + "a216", "a217", "a218", "a219", "a220", "a221", "a222", "a223", "a224", + "a225", "a226", "a227", "a228", "a229", "a230", "a231", "a232", "a233", + "a234", "a235", "a236", "a237", "a238", "a239", "a240", "a241", "a242", + "a243", "a244", "a245", "a246", "a247", "a248", "a249", "a250", "a251", + "a252", "a253", "a254", "a255" }; ArrayRef AMDGPUTargetInfo::getGCCRegNames() const { @@ -242,28 +271,6 @@ bool AMDGPUTargetInfo::initFeatureMap( return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec); } -void AMDGPUTargetInfo::adjustTargetOptions(const CodeGenOptions &CGOpts, - TargetOptions &TargetOpts) const { - bool hasFP32Denormals = false; - bool hasFP64Denormals = false; - - for (auto &I : TargetOpts.FeaturesAsWritten) { - if (I == "+fp32-denormals" || I == "-fp32-denormals") - hasFP32Denormals = true; - if (I == "+fp64-fp16-denormals" || I == "-fp64-fp16-denormals") - hasFP64Denormals = true; - } - if (!hasFP32Denormals) - TargetOpts.Features.push_back( - (Twine(hasFastFMAF() && hasFullRateDenormalsF32() && - CGOpts.FP32DenormalMode.Output == llvm::DenormalMode::IEEE - ? '+' : '-') + Twine("fp32-denormals")) - .str()); - // Always do not flush fp64 or fp16 denorms. - if (!hasFP64Denormals && hasFP64()) - TargetOpts.Features.push_back("+fp64-fp16-denormals"); -} - void AMDGPUTargetInfo::fillValidCPUList( SmallVectorImpl &Values) const { if (isAMDGCN(getTriple())) diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index ed6929214f6e0..548cadcab9ab8 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -114,11 +114,14 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { /// Accepted register names: (n, m is unsigned integer, n < m) /// v /// s + /// a /// {vn}, {v[n]} /// {sn}, {s[n]} + /// {an}, {a[n]} /// {S} , where S is a special register name ////{v[n:m]} /// {s[n:m]} + /// {a[n:m]} bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { static const ::llvm::StringSet<> SpecialRegs({ @@ -135,7 +138,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { } if (S.empty()) return false; - if (S.front() != 'v' && S.front() != 's') { + if (S.front() != 'v' && S.front() != 's' && S.front() != 'a') { if (!HasLeftParen) return false; auto E = S.find('}'); @@ -153,7 +156,7 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { if (!HasLeftParen) { if (!S.empty()) return false; - // Found s or v. + // Found s, v or a. Info.setAllowsRegister(); Name = S.data() - 1; return true; @@ -184,7 +187,8 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { S = S.drop_front(); if (!S.empty()) return false; - // Found {vn}, {sn}, {v[n]}, {s[n]}, {v[n:m]}, or {s[n:m]}. + // Found {vn}, {sn}, {an}, {v[n]}, {s[n]}, {a[n]}, {v[n:m]}, {s[n:m]} + // or {a[n:m]}. Info.setAllowsRegister(); Name = S.data() - 1; return true; @@ -208,9 +212,6 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { StringRef CPU, const std::vector &FeatureVec) const override; - void adjustTargetOptions(const CodeGenOptions &CGOpts, - TargetOptions &TargetOpts) const override; - ArrayRef getTargetBuiltins() const override; void getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 4ab794ef3c091..8815161815386 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -201,6 +201,8 @@ StringRef ARMTargetInfo::getCPUAttr() const { return "8_4A"; case llvm::ARM::ArchKind::ARMV8_5A: return "8_5A"; + case llvm::ARM::ArchKind::ARMV8_6A: + return "8_6A"; case llvm::ARM::ArchKind::ARMV8MBaseline: return "8M_BASE"; case llvm::ARM::ArchKind::ARMV8MMainline: @@ -830,6 +832,7 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::ARM::ArchKind::ARMV8_3A: case llvm::ARM::ArchKind::ARMV8_4A: case llvm::ARM::ArchKind::ARMV8_5A: + case llvm::ARM::ArchKind::ARMV8_6A: getTargetDefinesARMV83A(Opts, Builder); break; } diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index b2f1831e960e6..43e55dfbfb2b2 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -35,9 +35,9 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { Int64Type = SignedLong; RegParmMax = 5; if (Triple.getArch() == llvm::Triple::bpfeb) { - resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128"); + resetDataLayout("E-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); } else { - resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); + resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"); } MaxAtomicPromoteWidth = 64; MaxAtomicInlineWidth = 64; diff --git a/clang/lib/Basic/Targets/Hexagon.h b/clang/lib/Basic/Targets/Hexagon.h index f58f594b104fe..7e173df816839 100644 --- a/clang/lib/Basic/Targets/Hexagon.h +++ b/clang/lib/Basic/Targets/Hexagon.h @@ -57,6 +57,7 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { LargeArrayAlign = 64; UseBitFieldTypeAlignment = true; ZeroLengthBitfieldBoundary = 32; + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; // These are the default values anyway, but explicitly make sure // that the size of the boolean type is 8 bits. Bool vectors are used @@ -103,6 +104,8 @@ class LLVM_LIBRARY_VISIBILITY HexagonTargetInfo : public TargetInfo { DiagnosticsEngine &Diags) override; BuiltinVaListKind getBuiltinVaListKind() const override { + if (getTriple().isMusl()) + return TargetInfo::HexagonBuiltinVaList; return TargetInfo::CharPtrBuiltinVaList; } diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 7b575f52bb22d..def23a65edde7 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -857,6 +857,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasINVPCID = true; } else if (Feature == "+enqcmd") { HasENQCMD = true; + } else if (Feature == "+serialize") { + HasSERIALIZE = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) @@ -1247,6 +1249,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__INVPCID__"); if (HasENQCMD) Builder.defineMacro("__ENQCMD__"); + if (HasSERIALIZE) + Builder.defineMacro("__SERIALIZE__"); // Each case falls through to the previous one here. switch (SSELevel) { @@ -1390,6 +1394,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const { .Case("rdseed", true) .Case("rtm", true) .Case("sahf", true) + .Case("serialize", true) .Case("sgx", true) .Case("sha", true) .Case("shstk", true) @@ -1474,6 +1479,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("retpoline-external-thunk", HasRetpolineExternalThunk) .Case("rtm", HasRTM) .Case("sahf", HasLAHFSAHF) + .Case("serialize", HasSERIALIZE) .Case("sgx", HasSGX) .Case("sha", HasSHA) .Case("shstk", HasSHSTK) @@ -1731,6 +1737,120 @@ bool X86TargetInfo::validateAsmConstraint( } } +// Below is based on the following information: +// +------------------------------------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +// | Processor Name | Cache Line Size (Bytes) | Source | +// +------------------------------------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +// | i386 | 64 | https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf | +// | i486 | 16 | "four doublewords" (doubleword = 32 bits, 4 bits * 32 bits = 16 bytes) https://en.wikichip.org/w/images/d/d3/i486_MICROPROCESSOR_HARDWARE_REFERENCE_MANUAL_%281990%29.pdf and http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.126.4216&rep=rep1&type=pdf (page 29) | +// | i586/Pentium MMX | 32 | https://www.7-cpu.com/cpu/P-MMX.html | +// | i686/Pentium | 32 | https://www.7-cpu.com/cpu/P6.html | +// | Netburst/Pentium4 | 64 | https://www.7-cpu.com/cpu/P4-180.html | +// | Atom | 64 | https://www.7-cpu.com/cpu/Atom.html | +// | Westmere | 64 | https://en.wikichip.org/wiki/intel/microarchitectures/sandy_bridge_(client) "Cache Architecture" | +// | Sandy Bridge | 64 | https://en.wikipedia.org/wiki/Sandy_Bridge and https://www.7-cpu.com/cpu/SandyBridge.html | +// | Ivy Bridge | 64 | https://blog.stuffedcow.net/2013/01/ivb-cache-replacement/ and https://www.7-cpu.com/cpu/IvyBridge.html | +// | Haswell | 64 | https://www.7-cpu.com/cpu/Haswell.html | +// | Boadwell | 64 | https://www.7-cpu.com/cpu/Broadwell.html | +// | Skylake (including skylake-avx512) | 64 | https://www.nas.nasa.gov/hecc/support/kb/skylake-processors_550.html "Cache Hierarchy" | +// | Cascade Lake | 64 | https://www.nas.nasa.gov/hecc/support/kb/cascade-lake-processors_579.html "Cache Hierarchy" | +// | Skylake | 64 | https://en.wikichip.org/wiki/intel/microarchitectures/kaby_lake "Memory Hierarchy" | +// | Ice Lake | 64 | https://www.7-cpu.com/cpu/Ice_Lake.html | +// | Knights Landing | 64 | https://software.intel.com/en-us/articles/intel-xeon-phi-processor-7200-family-memory-management-optimizations "The Intel® Xeon Phi™ Processor Architecture" | +// | Knights Mill | 64 | https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf?countrylabel=Colombia "2.5.5.2 L1 DCache " | +// +------------------------------------+-------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+ +Optional X86TargetInfo::getCPUCacheLineSize() const { + switch (CPU) { + // i386 + case CK_i386: + // i486 + case CK_i486: + case CK_WinChipC6: + case CK_WinChip2: + case CK_C3: + // Lakemont + case CK_Lakemont: + return 16; + + // i586 + case CK_i586: + case CK_Pentium: + case CK_PentiumMMX: + // i686 + case CK_PentiumPro: + case CK_i686: + case CK_Pentium2: + case CK_Pentium3: + case CK_PentiumM: + case CK_C3_2: + // K6 + case CK_K6: + case CK_K6_2: + case CK_K6_3: + // Geode + case CK_Geode: + return 32; + + // Netburst + case CK_Pentium4: + case CK_Prescott: + case CK_Nocona: + // Atom + case CK_Bonnell: + case CK_Silvermont: + case CK_Goldmont: + case CK_GoldmontPlus: + case CK_Tremont: + + case CK_Westmere: + case CK_SandyBridge: + case CK_IvyBridge: + case CK_Haswell: + case CK_Broadwell: + case CK_SkylakeClient: + case CK_SkylakeServer: + case CK_Cascadelake: + case CK_Nehalem: + case CK_Cooperlake: + case CK_Cannonlake: + case CK_Tigerlake: + case CK_IcelakeClient: + case CK_IcelakeServer: + case CK_KNL: + case CK_KNM: + // K7 + case CK_Athlon: + case CK_AthlonXP: + // K8 + case CK_K8: + case CK_K8SSE3: + case CK_AMDFAM10: + // Bobcat + case CK_BTVER1: + case CK_BTVER2: + // Bulldozer + case CK_BDVER1: + case CK_BDVER2: + case CK_BDVER3: + case CK_BDVER4: + // Zen + case CK_ZNVER1: + case CK_ZNVER2: + // Deprecated + case CK_x86_64: + case CK_Yonah: + case CK_Penryn: + case CK_Core2: + return 64; + + // The following currently have unknown cache line sizes (but they are probably all 64): + // Core + case CK_Generic: + return None; + } + llvm_unreachable("Unknown CPU kind"); +} + bool X86TargetInfo::validateOutputSize(const llvm::StringMap &FeatureMap, StringRef Constraint, unsigned Size) const { diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 3166e2cce080b..155918dfc9335 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -129,6 +129,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasPTWRITE = false; bool HasINVPCID = false; bool HasENQCMD = false; + bool HasSERIALIZE = false; protected: /// Enumeration of all of the X86 CPUs supported by Clang. @@ -187,6 +188,8 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { StringRef Name, llvm::SmallVectorImpl &Features) const override; + Optional getCPUCacheLineSize() const override; + bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index b8a59bcdab391..14cc06fbef1ca 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1117,6 +1117,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( PTO.LoopInterleaving = CodeGenOpts.UnrollLoops; PTO.LoopVectorization = CodeGenOpts.VectorizeLoop; PTO.SLPVectorization = CodeGenOpts.VectorizeSLP; + PTO.CallGraphProfile = CodeGenOpts.CallGraphProfile; PTO.Coroutines = LangOpts.Coroutines; PassInstrumentationCallbacks PIC; @@ -1530,6 +1531,7 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, Conf.PTO.LoopInterleaving = CGOpts.UnrollLoops; Conf.PTO.LoopVectorization = CGOpts.VectorizeLoop; Conf.PTO.SLPVectorization = CGOpts.VectorizeSLP; + Conf.PTO.CallGraphProfile = CGOpts.CallGraphProfile; // Context sensitive profile. if (CGOpts.hasProfileCSIRInstr()) { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index b9327197c8423..50430197a70ab 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13413,6 +13413,48 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, } } +namespace { +// If \p E is not null pointer, insert address space cast to match return +// type of \p E if necessary. +Value *EmitAMDGPUDispatchPtr(CodeGenFunction &CGF, + const CallExpr *E = nullptr) { + auto *F = CGF.CGM.getIntrinsic(Intrinsic::amdgcn_dispatch_ptr); + auto *Call = CGF.Builder.CreateCall(F); + Call->addAttribute( + AttributeList::ReturnIndex, + Attribute::getWithDereferenceableBytes(Call->getContext(), 64)); + Call->addAttribute(AttributeList::ReturnIndex, + Attribute::getWithAlignment(Call->getContext(), Align(4))); + if (!E) + return Call; + QualType BuiltinRetType = E->getType(); + auto *RetTy = cast(CGF.ConvertType(BuiltinRetType)); + if (RetTy == Call->getType()) + return Call; + return CGF.Builder.CreateAddrSpaceCast(Call, RetTy); +} + +// \p Index is 0, 1, and 2 for x, y, and z dimension, respectively. +Value *EmitAMDGPUWorkGroupSize(CodeGenFunction &CGF, unsigned Index) { + const unsigned XOffset = 4; + auto *DP = EmitAMDGPUDispatchPtr(CGF); + // Indexing the HSA kernel_dispatch_packet struct. + auto *Offset = llvm::ConstantInt::get(CGF.Int32Ty, XOffset + Index * 2); + auto *GEP = CGF.Builder.CreateGEP(DP, Offset); + auto *DstTy = + CGF.Int16Ty->getPointerTo(GEP->getType()->getPointerAddressSpace()); + auto *Cast = CGF.Builder.CreateBitCast(GEP, DstTy); + auto *LD = CGF.Builder.CreateLoad(Address(Cast, CharUnits::fromQuantity(2))); + llvm::MDBuilder MDHelper(CGF.getLLVMContext()); + llvm::MDNode *RNode = MDHelper.createRange(APInt(16, 1), + APInt(16, CGF.getTarget().getMaxOpenCLWorkGroupSize() + 1)); + LD->setMetadata(llvm::LLVMContext::MD_range, RNode); + LD->setMetadata(llvm::LLVMContext::MD_invariant_load, + llvm::MDNode::get(CGF.getLLVMContext(), None)); + return LD; +} +} // namespace + Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { switch (BuiltinID) { @@ -13495,21 +13537,8 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_cosf: case AMDGPU::BI__builtin_amdgcn_cosh: return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_cos); - case AMDGPU::BI__builtin_amdgcn_dispatch_ptr: { - auto *F = CGM.getIntrinsic(Intrinsic::amdgcn_dispatch_ptr); - auto *Call = Builder.CreateCall(F); - Call->addAttribute( - AttributeList::ReturnIndex, - Attribute::getWithDereferenceableBytes(Call->getContext(), 64)); - Call->addAttribute( - AttributeList::ReturnIndex, - Attribute::getWithAlignment(Call->getContext(), Align(4))); - QualType BuiltinRetType = E->getType(); - auto *RetTy = cast(ConvertType(BuiltinRetType)); - if (RetTy == Call->getType()) - return Call; - return Builder.CreateAddrSpaceCast(Call, RetTy); - } + case AMDGPU::BI__builtin_amdgcn_dispatch_ptr: + return EmitAMDGPUDispatchPtr(*this, E); case AMDGPU::BI__builtin_amdgcn_log_clampf: return emitUnaryBuiltin(*this, E, Intrinsic::amdgcn_log_clamp); case AMDGPU::BI__builtin_amdgcn_ldexp: @@ -13605,6 +13634,14 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_workitem_id_z: return emitRangedBuiltin(*this, Intrinsic::amdgcn_workitem_id_z, 0, 1024); + // amdgcn workgroup size + case AMDGPU::BI__builtin_amdgcn_workgroup_size_x: + return EmitAMDGPUWorkGroupSize(*this, 0); + case AMDGPU::BI__builtin_amdgcn_workgroup_size_y: + return EmitAMDGPUWorkGroupSize(*this, 1); + case AMDGPU::BI__builtin_amdgcn_workgroup_size_z: + return EmitAMDGPUWorkGroupSize(*this, 2); + // r600 intrinsics case AMDGPU::BI__builtin_r600_recipsqrt_ieee: case AMDGPU::BI__builtin_r600_recipsqrt_ieeef: diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 5d8e545050d9b..351c5058aa4c9 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -50,7 +50,7 @@ class CGNVCUDARuntime : public CGCUDARuntime { struct VarInfo { llvm::GlobalVariable *Var; const VarDecl *D; - unsigned Flag; + DeviceVarFlags Flags; }; llvm::SmallVector DeviceVars; /// Keeps track of variable containing handle of GPU binary. Populated by @@ -124,8 +124,25 @@ class CGNVCUDARuntime : public CGCUDARuntime { void emitDeviceStub(CodeGenFunction &CGF, FunctionArgList &Args) override; void registerDeviceVar(const VarDecl *VD, llvm::GlobalVariable &Var, - unsigned Flags) override { - DeviceVars.push_back({&Var, VD, Flags}); + bool Extern, bool Constant) override { + DeviceVars.push_back({&Var, + VD, + {DeviceVarFlags::Variable, Extern, Constant, + /*Normalized*/ false, /*Type*/ 0}}); + } + void registerDeviceSurf(const VarDecl *VD, llvm::GlobalVariable &Var, + bool Extern, int Type) override { + DeviceVars.push_back({&Var, + VD, + {DeviceVarFlags::Surface, Extern, /*Constant*/ false, + /*Normalized*/ false, Type}}); + } + void registerDeviceTex(const VarDecl *VD, llvm::GlobalVariable &Var, + bool Extern, int Type, bool Normalized) override { + DeviceVars.push_back({&Var, + VD, + {DeviceVarFlags::Texture, Extern, /*Constant*/ false, + Normalized, Type}}); } /// Creates module constructor function @@ -423,30 +440,70 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() { Builder.CreateCall(RegisterFunc, Args); } + llvm::Type *VarSizeTy = IntTy; + // For HIP or CUDA 9.0+, device variable size is type of `size_t`. + if (CGM.getLangOpts().HIP || + ToCudaVersion(CGM.getTarget().getSDKVersion()) >= CudaVersion::CUDA_90) + VarSizeTy = SizeTy; + // void __cudaRegisterVar(void **, char *, char *, const char *, // int, int, int, int) llvm::Type *RegisterVarParams[] = {VoidPtrPtrTy, CharPtrTy, CharPtrTy, - CharPtrTy, IntTy, IntTy, + CharPtrTy, IntTy, VarSizeTy, IntTy, IntTy}; llvm::FunctionCallee RegisterVar = CGM.CreateRuntimeFunction( - llvm::FunctionType::get(IntTy, RegisterVarParams, false), + llvm::FunctionType::get(VoidTy, RegisterVarParams, false), addUnderscoredPrefixToName("RegisterVar")); + // void __cudaRegisterSurface(void **, const struct surfaceReference *, + // const void **, const char *, int, int); + llvm::FunctionCallee RegisterSurf = CGM.CreateRuntimeFunction( + llvm::FunctionType::get( + VoidTy, {VoidPtrPtrTy, VoidPtrTy, CharPtrTy, CharPtrTy, IntTy, IntTy}, + false), + addUnderscoredPrefixToName("RegisterSurface")); + // void __cudaRegisterTexture(void **, const struct textureReference *, + // const void **, const char *, int, int, int) + llvm::FunctionCallee RegisterTex = CGM.CreateRuntimeFunction( + llvm::FunctionType::get( + VoidTy, + {VoidPtrPtrTy, VoidPtrTy, CharPtrTy, CharPtrTy, IntTy, IntTy, IntTy}, + false), + addUnderscoredPrefixToName("RegisterTexture")); for (auto &&Info : DeviceVars) { llvm::GlobalVariable *Var = Info.Var; - unsigned Flags = Info.Flag; llvm::Constant *VarName = makeConstantString(getDeviceSideName(Info.D)); - uint64_t VarSize = - CGM.getDataLayout().getTypeAllocSize(Var->getValueType()); - llvm::Value *Args[] = { - &GpuBinaryHandlePtr, - Builder.CreateBitCast(Var, VoidPtrTy), - VarName, - VarName, - llvm::ConstantInt::get(IntTy, (Flags & ExternDeviceVar) ? 1 : 0), - llvm::ConstantInt::get(IntTy, VarSize), - llvm::ConstantInt::get(IntTy, (Flags & ConstantDeviceVar) ? 1 : 0), - llvm::ConstantInt::get(IntTy, 0)}; - Builder.CreateCall(RegisterVar, Args); + switch (Info.Flags.getKind()) { + case DeviceVarFlags::Variable: { + uint64_t VarSize = + CGM.getDataLayout().getTypeAllocSize(Var->getValueType()); + llvm::Value *Args[] = { + &GpuBinaryHandlePtr, + Builder.CreateBitCast(Var, VoidPtrTy), + VarName, + VarName, + llvm::ConstantInt::get(IntTy, Info.Flags.isExtern()), + llvm::ConstantInt::get(VarSizeTy, VarSize), + llvm::ConstantInt::get(IntTy, Info.Flags.isConstant()), + llvm::ConstantInt::get(IntTy, 0)}; + Builder.CreateCall(RegisterVar, Args); + break; + } + case DeviceVarFlags::Surface: + Builder.CreateCall( + RegisterSurf, + {&GpuBinaryHandlePtr, Builder.CreateBitCast(Var, VoidPtrTy), VarName, + VarName, llvm::ConstantInt::get(IntTy, Info.Flags.getSurfTexType()), + llvm::ConstantInt::get(IntTy, Info.Flags.isExtern())}); + break; + case DeviceVarFlags::Texture: + Builder.CreateCall( + RegisterTex, + {&GpuBinaryHandlePtr, Builder.CreateBitCast(Var, VoidPtrTy), VarName, + VarName, llvm::ConstantInt::get(IntTy, Info.Flags.getSurfTexType()), + llvm::ConstantInt::get(IntTy, Info.Flags.isNormalized()), + llvm::ConstantInt::get(IntTy, Info.Flags.isExtern())}); + break; + } } Builder.CreateRetVoid(); diff --git a/clang/lib/CodeGen/CGCUDARuntime.h b/clang/lib/CodeGen/CGCUDARuntime.h index 330e950c98eb9..19e70a2022a51 100644 --- a/clang/lib/CodeGen/CGCUDARuntime.h +++ b/clang/lib/CodeGen/CGCUDARuntime.h @@ -42,9 +42,30 @@ class CGCUDARuntime { public: // Global variable properties that must be passed to CUDA runtime. - enum DeviceVarFlags { - ExternDeviceVar = 0x01, // extern - ConstantDeviceVar = 0x02, // __constant__ + class DeviceVarFlags { + public: + enum DeviceVarKind { + Variable, // Variable + Surface, // Builtin surface + Texture, // Builtin texture + }; + + private: + unsigned Kind : 2; + unsigned Extern : 1; + unsigned Constant : 1; // Constant variable. + unsigned Normalized : 1; // Normalized texture. + int SurfTexType; // Type of surface/texutre. + + public: + DeviceVarFlags(DeviceVarKind K, bool E, bool C, bool N, int T) + : Kind(K), Extern(E), Constant(C), Normalized(N), SurfTexType(T) {} + + DeviceVarKind getKind() const { return static_cast(Kind); } + bool isExtern() const { return Extern; } + bool isConstant() const { return Constant; } + bool isNormalized() const { return Normalized; } + int getSurfTexType() const { return SurfTexType; } }; CGCUDARuntime(CodeGenModule &CGM) : CGM(CGM) {} @@ -57,7 +78,11 @@ class CGCUDARuntime { /// Emits a kernel launch stub. virtual void emitDeviceStub(CodeGenFunction &CGF, FunctionArgList &Args) = 0; virtual void registerDeviceVar(const VarDecl *VD, llvm::GlobalVariable &Var, - unsigned Flags) = 0; + bool Extern, bool Constant) = 0; + virtual void registerDeviceSurf(const VarDecl *VD, llvm::GlobalVariable &Var, + bool Extern, int Type) = 0; + virtual void registerDeviceTex(const VarDecl *VD, llvm::GlobalVariable &Var, + bool Extern, int Type, bool Normalized) = 0; /// Constructs and returns a module initialization function or nullptr if it's /// not needed. Must be called after all kernels have been emitted. diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index da6cb458982ba..6d3c2ad66cdca 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1817,9 +1817,10 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, if (auto *templateType = dyn_cast_or_null(TPList->getParam(i))) if (templateType->hasDefaultArgument()) - defaultParameter = + defaultParameter = llvm::APSInt::isSameValue( templateType->getDefaultArgument()->EvaluateKnownConstInt( - CGM.getContext()) == TA.getAsIntegral(); + CGM.getContext()), + TA.getAsIntegral()); TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, defaultParameter, @@ -2483,6 +2484,17 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod, assert(StringRef(M->Name).startswith(CGM.getLangOpts().ModuleName) && "clang module without ASTFile must be specified by -fmodule-name"); + // Return a StringRef to the remapped Path. + auto RemapPath = [this](StringRef Path) -> std::string { + std::string Remapped = remapDIPath(Path); + StringRef Relative(Remapped); + StringRef CompDir = TheCU->getDirectory(); + if (Relative.consume_front(CompDir)) + Relative.consume_front(llvm::sys::path::get_separator()); + + return Relative.str(); + }; + if (CreateSkeletonCU && IsRootModule && !Mod.getASTFile().empty()) { // PCH files don't have a signature field in the control block, // but LLVM detects skeleton CUs by looking for a non-zero DWO id. @@ -2496,16 +2508,12 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod, if (!llvm::sys::path::is_absolute(Mod.getASTFile())) PCM = Mod.getPath(); llvm::sys::path::append(PCM, Mod.getASTFile()); - std::string RemappedPCM = remapDIPath(PCM); - StringRef RelativePCM(RemappedPCM); - StringRef CompDir = TheCU->getDirectory(); - if (RelativePCM.consume_front(CompDir)) - RelativePCM.consume_front(llvm::sys::path::get_separator()); - DIB.createCompileUnit(TheCU->getSourceLanguage(), - // TODO: Support "Source" from external AST providers? - DIB.createFile(Mod.getModuleName(), CompDir), - TheCU->getProducer(), false, StringRef(), 0, RelativePCM, - llvm::DICompileUnit::FullDebug, Signature); + DIB.createCompileUnit( + TheCU->getSourceLanguage(), + // TODO: Support "Source" from external AST providers? + DIB.createFile(Mod.getModuleName(), TheCU->getDirectory()), + TheCU->getProducer(), false, StringRef(), 0, RemapPath(PCM), + llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } @@ -2513,9 +2521,10 @@ llvm::DIModule *CGDebugInfo::getOrCreateModuleRef(ASTSourceDescriptor Mod, IsRootModule ? nullptr : getOrCreateModuleRef(ASTSourceDescriptor(*M->Parent), CreateSkeletonCU); + std::string IncludePath = Mod.getPath().str(); llvm::DIModule *DIMod = DBuilder.createModule(Parent, Mod.getModuleName(), ConfigMacros, - Mod.getPath()); + RemapPath(IncludePath)); ModuleCache[M].reset(DIMod); return DIMod; } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 74a63ea9b899b..f15049ab0b5df 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1102,7 +1102,9 @@ static llvm::Constant *constWithPadding(CodeGenModule &CGM, IsPattern isPattern, auto *NewArrayTy = llvm::ArrayType::get(NewElemTy, Size); return llvm::ConstantArray::get(NewArrayTy, Values); } - // FIXME: Do we need to handle tail padding in vectors? + // FIXME: Add handling for tail padding in vectors. Vectors don't + // have padding between or inside elements, but the total amount of + // data can be less than the allocated size. return constant; } diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index 0c6f0e71942fb..e501e53e4cb1b 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -16,7 +16,7 @@ #include "CodeGenFunction.h" #include "TargetInfo.h" #include "clang/AST/Attr.h" -#include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/LangOptions.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" @@ -396,20 +396,20 @@ llvm::Function *CodeGenModule::CreateGlobalInitOrDestructFunction( !isInSanitizerBlacklist(SanitizerKind::ShadowCallStack, Fn, Loc)) Fn->addFnAttr(llvm::Attribute::ShadowCallStack); - auto RASignKind = getCodeGenOpts().getSignReturnAddress(); - if (RASignKind != CodeGenOptions::SignReturnAddressScope::None) { + auto RASignKind = getLangOpts().getSignReturnAddressScope(); + if (RASignKind != LangOptions::SignReturnAddressScopeKind::None) { Fn->addFnAttr("sign-return-address", - RASignKind == CodeGenOptions::SignReturnAddressScope::All + RASignKind == LangOptions::SignReturnAddressScopeKind::All ? "all" : "non-leaf"); - auto RASignKey = getCodeGenOpts().getSignReturnAddressKey(); + auto RASignKey = getLangOpts().getSignReturnAddressKey(); Fn->addFnAttr("sign-return-address-key", - RASignKey == CodeGenOptions::SignReturnAddressKeyValue::AKey + RASignKey == LangOptions::SignReturnAddressKeyKind::AKey ? "a_key" : "b_key"); } - if (getCodeGenOpts().BranchTargetEnforcement) + if (getLangOpts().BranchTargetEnforcement) Fn->addFnAttr("branch-target-enforcement"); return Fn; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 4b5b2a5454062..1d4ba22d14c3f 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1674,7 +1674,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, // Shuffle vector to get vec3. V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty), - {0, 1, 2}, "extractVec"); + ArrayRef{0, 1, 2}, "extractVec"); return EmitFromMemory(V, Ty); } } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index df576decd69d6..fa2d228b7eeb0 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -15,6 +15,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" @@ -1946,6 +1947,18 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty, } } + if (getLangOpts().CUDAIsDevice) { + if (Ty->isCUDADeviceBuiltinSurfaceType()) { + if (getTargetHooks().emitCUDADeviceBuiltinSurfaceDeviceCopy(*this, Dest, + Src)) + return; + } else if (Ty->isCUDADeviceBuiltinTextureType()) { + if (getTargetHooks().emitCUDADeviceBuiltinTextureDeviceCopy(*this, Dest, + Src)) + return; + } + } + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index e17c1c5f7ac4f..da5d778a4922b 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -589,19 +589,21 @@ bool ConstStructBuilder::AppendBytes(CharUnits FieldOffsetInChars, bool ConstStructBuilder::AppendBitField( const FieldDecl *Field, uint64_t FieldOffset, llvm::ConstantInt *CI, bool AllowOverwrite) { - uint64_t FieldSize = Field->getBitWidthValue(CGM.getContext()); + const CGRecordLayout &RL = + CGM.getTypes().getCGRecordLayout(Field->getParent()); + const CGBitFieldInfo &Info = RL.getBitFieldInfo(Field); llvm::APInt FieldValue = CI->getValue(); // Promote the size of FieldValue if necessary // FIXME: This should never occur, but currently it can because initializer // constants are cast to bool, and because clang is not enforcing bitfield // width limits. - if (FieldSize > FieldValue.getBitWidth()) - FieldValue = FieldValue.zext(FieldSize); + if (Info.Size > FieldValue.getBitWidth()) + FieldValue = FieldValue.zext(Info.Size); // Truncate the size of FieldValue to the bit field size. - if (FieldSize < FieldValue.getBitWidth()) - FieldValue = FieldValue.trunc(FieldSize); + if (Info.Size < FieldValue.getBitWidth()) + FieldValue = FieldValue.trunc(Info.Size); return Builder.addBits(FieldValue, CGM.getContext().toBits(StartOffset) + FieldOffset, diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index db78309e9fd9f..35b9268084922 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -617,6 +617,13 @@ class CGObjCGNU : public CGObjCRuntime { llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, const ObjCProtocolDecl *PD) override; void GenerateProtocol(const ObjCProtocolDecl *PD) override; + + virtual llvm::Constant *GenerateProtocolRef(const ObjCProtocolDecl *PD); + + llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override { + return GenerateProtocolRef(PD); + } + llvm::Function *ModuleInitFunction() override; llvm::FunctionCallee GetPropertyGetFunction() override; llvm::FunctionCallee GetPropertySetFunction() override; @@ -1348,7 +1355,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { void GenerateProtocol(const ObjCProtocolDecl *PD) override { // Do nothing - we only emit referenced protocols. } - llvm::Constant *GenerateProtocolRef(const ObjCProtocolDecl *PD) { + llvm::Constant *GenerateProtocolRef(const ObjCProtocolDecl *PD) override { std::string ProtocolName = PD->getNameAsString(); auto *&Protocol = ExistingProtocols[ProtocolName]; if (Protocol) @@ -3039,13 +3046,18 @@ CGObjCGNU::GenerateProtocolList(ArrayRef Protocols) { llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF, const ObjCProtocolDecl *PD) { + auto protocol = GenerateProtocolRef(PD); + llvm::Type *T = + CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); + return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); +} + +llvm::Constant *CGObjCGNU::GenerateProtocolRef(const ObjCProtocolDecl *PD) { llvm::Constant *&protocol = ExistingProtocols[PD->getNameAsString()]; if (!protocol) GenerateProtocol(PD); assert(protocol && "Unknown protocol"); - llvm::Type *T = - CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); - return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); + return protocol; } llvm::Constant * diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 87fd51b5d8b11..3986310eaa706 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1107,11 +1107,6 @@ class CGObjCCommonMac : public CodeGen::CGObjCRuntime { void GenerateProtocol(const ObjCProtocolDecl *PD) override; - /// GetOrEmitProtocol - Get the protocol object for the given - /// declaration, emitting it if necessary. The return value has type - /// ProtocolPtrTy. - virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD)=0; - /// GetOrEmitProtocolRef - Get a forward reference to the protocol /// object for the given declaration, emitting it if needed. These /// forward references will be filled in with empty bodies if no diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index c34758c7e3b3f..39efe040302d3 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -13,14 +13,15 @@ //===----------------------------------------------------------------------===// #include "CGObjCRuntime.h" -#include "CGCleanup.h" #include "CGCXXABI.h" +#include "CGCleanup.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtObjC.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "clang/CodeGen/CodeGenABITypes.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; @@ -383,3 +384,9 @@ CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method, CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(); return MessageSendInfo(argsInfo, signatureType); } + +llvm::Constant * +clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM, + const ObjCProtocolDecl *protocol) { + return CGM.getObjCRuntime().GetOrEmitProtocol(protocol); +} diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index f0b3525cfde25..a2c189585f7bc 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -211,6 +211,11 @@ class CGObjCRuntime { /// implementations. virtual void GenerateProtocol(const ObjCProtocolDecl *OPD) = 0; + /// GetOrEmitProtocol - Get the protocol object for the given + /// declaration, emitting it if necessary. The return value has type + /// ProtocolPtrTy. + virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) = 0; + /// Generate a function preamble for a method with the specified /// types. diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 58c5334776f3f..6642851a56bc6 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1275,52 +1275,6 @@ CGOpenMPRuntime::CGOpenMPRuntime(CodeGenModule &CGM, StringRef FirstSeparator, loadOffloadInfoMetadata(); } -bool CGOpenMPRuntime::tryEmitDeclareVariant(const GlobalDecl &NewGD, - const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition) { - // Emit at least a definition for the aliasee if the the address of the - // original function is requested. - if (IsForDefinition || OrigAddr) - (void)CGM.GetAddrOfGlobal(NewGD); - StringRef NewMangledName = CGM.getMangledName(NewGD); - llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName); - if (Addr && !Addr->isDeclaration()) { - const auto *D = cast(OldGD.getDecl()); - const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(NewGD); - llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI); - - // Create a reference to the named value. This ensures that it is emitted - // if a deferred decl. - llvm::GlobalValue::LinkageTypes LT = CGM.getFunctionLinkage(OldGD); - - // Create the new alias itself, but don't set a name yet. - auto *GA = - llvm::GlobalAlias::create(DeclTy, 0, LT, "", Addr, &CGM.getModule()); - - if (OrigAddr) { - assert(OrigAddr->isDeclaration() && "Expected declaration"); - - GA->takeName(OrigAddr); - OrigAddr->replaceAllUsesWith( - llvm::ConstantExpr::getBitCast(GA, OrigAddr->getType())); - OrigAddr->eraseFromParent(); - } else { - GA->setName(CGM.getMangledName(OldGD)); - } - - // Set attributes which are particular to an alias; this is a - // specialization of the attributes which may be set on a global function. - if (D->hasAttr() || D->hasAttr() || - D->isWeakImported()) - GA->setLinkage(llvm::Function::WeakAnyLinkage); - - CGM.SetCommonAttributes(OldGD, GA); - return true; - } - return false; -} - void CGOpenMPRuntime::clear() { InternalVars.clear(); // Clean non-target variable declarations possibly used only in debug info. @@ -1334,14 +1288,6 @@ void CGOpenMPRuntime::clear() { continue; GV->eraseFromParent(); } - // Emit aliases for the deferred aliasees. - for (const auto &Pair : DeferredVariantFunction) { - StringRef MangledName = CGM.getMangledName(Pair.second.second); - llvm::GlobalValue *Addr = CGM.GetGlobalValue(MangledName); - // If not able to emit alias, just emit original declaration. - (void)tryEmitDeclareVariant(Pair.second.first, Pair.second.second, Addr, - /*IsForDefinition=*/false); - } } std::string CGOpenMPRuntime::getName(ArrayRef Parts) const { @@ -5417,17 +5363,32 @@ std::pair CGOpenMPRuntime::emitDependClause( if (Dependencies[I].first == OMPC_DEPEND_depobj) continue; const Expr *E = Dependencies[I].second; - LValue Addr = CGF.EmitLValue(E); + const auto *OASE = dyn_cast(E); + llvm::Value *Addr; + if (OASE) { + const Expr *Base = OASE->getBase(); + Addr = CGF.EmitScalarExpr(Base); + } else { + Addr = CGF.EmitLValue(E).getPointer(CGF); + } llvm::Value *Size; QualType Ty = E->getType(); - if (const auto *ASE = - dyn_cast(E->IgnoreParenImpCasts())) { + if (OASE) { + Size = CGF.getTypeSize(OASE->getBase()->getType()->getPointeeType()); + for (const Expr *SE : OASE->getDimensions()) { + llvm::Value *Sz = CGF.EmitScalarExpr(SE); + Sz = CGF.EmitScalarConversion(Sz, SE->getType(), + CGF.getContext().getSizeType(), + SE->getExprLoc()); + Size = CGF.Builder.CreateNUWMul(Size, Sz); + } + } else if (const auto *ASE = + dyn_cast(E->IgnoreParenImpCasts())) { LValue UpAddrLVal = CGF.EmitOMPArraySectionExpr(ASE, /*IsLowerBound=*/false); llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32( UpAddrLVal.getPointer(CGF), /*Idx0=*/1); - llvm::Value *LowIntPtr = - CGF.Builder.CreatePtrToInt(Addr.getPointer(CGF), CGM.SizeTy); + llvm::Value *LowIntPtr = CGF.Builder.CreatePtrToInt(Addr, CGM.SizeTy); llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGM.SizeTy); Size = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr); } else { @@ -5446,9 +5407,8 @@ std::pair CGOpenMPRuntime::emitDependClause( // deps[i].base_addr = &; LValue BaseAddrLVal = CGF.EmitLValueForField( Base, *std::next(KmpDependInfoRD->field_begin(), BaseAddr)); - CGF.EmitStoreOfScalar( - CGF.Builder.CreatePtrToInt(Addr.getPointer(CGF), CGF.IntPtrTy), - BaseAddrLVal); + CGF.EmitStoreOfScalar(CGF.Builder.CreatePtrToInt(Addr, CGF.IntPtrTy), + BaseAddrLVal); // deps[i].len = sizeof(); LValue LenLVal = CGF.EmitLValueForField( Base, *std::next(KmpDependInfoRD->field_begin(), Len)); @@ -7008,6 +6968,8 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF, case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -7321,6 +7283,8 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF, case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -7484,6 +7448,20 @@ class MappableExprsHandler { llvm::Value *getExprTypeSize(const Expr *E) const { QualType ExprTy = E->getType().getCanonicalType(); + // Calculate the size for array shaping expression. + if (const auto *OAE = dyn_cast(E)) { + llvm::Value *Size = + CGF.getTypeSize(OAE->getBase()->getType()->getPointeeType()); + for (const Expr *SE : OAE->getDimensions()) { + llvm::Value *Sz = CGF.EmitScalarExpr(SE); + Sz = CGF.EmitScalarConversion(Sz, SE->getType(), + CGF.getContext().getSizeType(), + SE->getExprLoc()); + Size = CGF.Builder.CreateNUWMul(Size, Sz); + } + return Size; + } + // Reference types are ignored for mapping purposes. if (const auto *RefTy = ExprTy->getAs()) ExprTy = RefTy->getPointeeType().getCanonicalType(); @@ -7815,6 +7793,7 @@ class MappableExprsHandler { const Expr *AssocExpr = I->getAssociatedExpression(); const auto *AE = dyn_cast(AssocExpr); const auto *OASE = dyn_cast(AssocExpr); + const auto *OAShE = dyn_cast(AssocExpr); if (isa(AssocExpr)) { // The base is the 'this' pointer. The content of the pointer is going @@ -7824,6 +7803,11 @@ class MappableExprsHandler { (OASE && isa(OASE->getBase()->IgnoreParenImpCasts()))) { BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(CGF); + } else if (OAShE && + isa(OAShE->getBase()->IgnoreParenCasts())) { + BP = Address( + CGF.EmitScalarExpr(OAShE->getBase()), + CGF.getContext().getTypeAlignInChars(OAShE->getBase()->getType())); } else { // The base is the reference to the variable. // BP = &Var. @@ -7906,9 +7890,12 @@ class MappableExprsHandler { // types. const auto *OASE = dyn_cast(I->getAssociatedExpression()); + const auto *OAShE = + dyn_cast(I->getAssociatedExpression()); const auto *UO = dyn_cast(I->getAssociatedExpression()); const auto *BO = dyn_cast(I->getAssociatedExpression()); bool IsPointer = + OAShE || (OASE && OMPArraySectionExpr::getBaseOriginalType(OASE) .getCanonicalType() ->isAnyPointerType()) || @@ -7926,8 +7913,15 @@ class MappableExprsHandler { isa(Next->getAssociatedExpression())) && "Unexpected expression"); - Address LB = CGF.EmitOMPSharedLValue(I->getAssociatedExpression()) - .getAddress(CGF); + Address LB = Address::invalid(); + if (OAShE) { + LB = Address(CGF.EmitScalarExpr(OAShE->getBase()), + CGF.getContext().getTypeAlignInChars( + OAShE->getBase()->getType())); + } else { + LB = CGF.EmitOMPSharedLValue(I->getAssociatedExpression()) + .getAddress(CGF); + } // If this component is a pointer inside the base struct then we don't // need to create any entry for it - it will be combined with the object @@ -9107,6 +9101,8 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) { case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -9886,6 +9882,8 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -10525,6 +10523,8 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( case OMPD_teams_distribute_parallel_for_simd: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -11383,56 +11383,6 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, return Address(Addr, Align); } -/// Finds the variant function that matches current context with its context -/// selector. -static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM, - const FunctionDecl *FD) { - if (!FD->hasAttrs() || !FD->hasAttr()) - return FD; - - SmallVector VariantExprs; - SmallVector VMIs; - for (const auto *A : FD->specific_attrs()) { - const OMPTraitInfo &TI = *A->getTraitInfos(); - VMIs.push_back(VariantMatchInfo()); - TI.getAsVariantMatchInfo(CGM.getContext(), VMIs.back()); - VariantExprs.push_back(A->getVariantFuncRef()); - } - - OMPContext Ctx(CGM.getLangOpts().OpenMPIsDevice, CGM.getTriple()); - // FIXME: Keep the context in the OMPIRBuilder so we can add constructs as we - // build them. - - int BestMatchIdx = getBestVariantMatchForContext(VMIs, Ctx); - if (BestMatchIdx < 0) - return FD; - - return cast( - cast(VariantExprs[BestMatchIdx]->IgnoreParenImpCasts()) - ->getDecl()); -} - -bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) { - const auto *D = cast(GD.getDecl()); - // If the original function is defined already, use its definition. - StringRef MangledName = CGM.getMangledName(GD); - llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName); - if (Orig && !Orig->isDeclaration()) - return false; - const FunctionDecl *NewFD = getDeclareVariantFunction(CGM, D); - // Emit original function if it does not have declare variant attribute or the - // context does not match. - if (NewFD == D) - return false; - GlobalDecl NewGD = GD.getWithDecl(NewFD); - if (tryEmitDeclareVariant(NewGD, GD, Orig, IsForDefinition)) { - DeferredVariantFunction.erase(D); - return true; - } - DeferredVariantFunction.insert(std::make_pair(D, std::make_pair(NewGD, GD))); - return true; -} - CGOpenMPRuntime::NontemporalDeclsRAII::NontemporalDeclsRAII( CodeGenModule &CGM, const OMPLoopDirective &S) : CGM(CGM), NeedToPush(S.hasClausesOfKind()) { diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index 99b201bcf6fea..122996030e868 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -334,17 +334,6 @@ class CGOpenMPRuntime { /// default location. virtual unsigned getDefaultLocationReserved2Flags() const { return 0; } - /// Tries to emit declare variant function for \p OldGD from \p NewGD. - /// \param OrigAddr LLVM IR value for \p OldGD. - /// \param IsForDefinition true, if requested emission for the definition of - /// \p OldGD. - /// \returns true, was able to emit a definition function for \p OldGD, which - /// points to \p NewGD. - virtual bool tryEmitDeclareVariant(const GlobalDecl &NewGD, - const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition); - /// Returns default flags for the barriers depending on the directive, for /// which this barier is going to be emitted. static unsigned getDefaultFlagsForBarriers(OpenMPDirectiveKind Kind); @@ -686,12 +675,6 @@ class CGOpenMPRuntime { /// must be emitted. llvm::SmallDenseSet DeferredGlobalVariables; - /// Mapping of the original functions to their variants and original global - /// decl. - llvm::MapVector, - std::pair> - DeferredVariantFunction; - using NontemporalDeclsSet = llvm::SmallDenseSet>; /// Stack for list of declarations in current context marked as nontemporal. /// The set is the union of all current stack elements. @@ -1726,9 +1709,6 @@ class CGOpenMPRuntime { /// Return whether the unified_shared_memory has been specified. bool hasRequiresUnifiedSharedMemory() const; - /// Emits the definition of the declare variant function. - virtual bool emitDeclareVariant(GlobalDecl GD, bool IsForDefinition); - /// Checks if the \p VD variable is marked as nontemporal declaration in /// current context. bool isNontemporalDecl(const ValueDecl *VD) const; diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp index 4b5c85541a7a5..aa6b6bc64c328 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -803,6 +803,8 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx, case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -881,6 +883,8 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -1052,6 +1056,8 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx, case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -1136,6 +1142,8 @@ static bool supportsLightweightRuntime(ASTContext &Ctx, case OMPD_target_update: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -1923,19 +1931,6 @@ unsigned CGOpenMPRuntimeNVPTX::getDefaultLocationReserved2Flags() const { llvm_unreachable("Unknown flags are requested."); } -bool CGOpenMPRuntimeNVPTX::tryEmitDeclareVariant(const GlobalDecl &NewGD, - const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition) { - // Emit the function in OldGD with the body from NewGD, if NewGD is defined. - auto *NewFD = cast(NewGD.getDecl()); - if (NewFD->isDefined()) { - CGM.emitOpenMPDeviceFunctionRedefinition(OldGD, NewGD, OrigAddr); - return true; - } - return false; -} - CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM) : CGOpenMPRuntime(CGM, "_", "$") { if (!CGM.getLangOpts().OpenMPIsDevice) diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h index 834adb3782a09..c52ae43817c75 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h @@ -193,18 +193,6 @@ class CGOpenMPRuntimeNVPTX : public CGOpenMPRuntime { /// Full/Lightweight runtime mode. Used for better optimization. unsigned getDefaultLocationReserved2Flags() const override; - /// Tries to emit declare variant function for \p OldGD from \p NewGD. - /// \param OrigAddr LLVM IR value for \p OldGD. - /// \param IsForDefinition true, if requested emission for the definition of - /// \p OldGD. - /// \returns true, was able to emit a definition function for \p OldGD, which - /// points to \p NewGD. - /// NVPTX backend does not support global aliases, so just use the function, - /// emitted for \p NewGD instead of \p OldGD. - bool tryEmitDeclareVariant(const GlobalDecl &NewGD, const GlobalDecl &OldGD, - llvm::GlobalValue *OrigAddr, - bool IsForDefinition) override; - public: explicit CGOpenMPRuntimeNVPTX(CodeGenModule &CGM); void clear() override; diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index bef36bf4693b2..af7056a10f00d 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -24,6 +24,7 @@ #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PrettyStackTrace.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/Support/AtomicOrdering.h" using namespace clang; @@ -3535,9 +3536,13 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( // initializer/combiner/finalizer. CGF.CGM.getOpenMPRuntime().emitTaskReductionFixups(CGF, S.getBeginLoc(), RedCG, Cnt); - llvm::Value *ReductionsPtr = - CGF.EmitLoadOfScalar(CGF.EmitLValue(TaskgroupDescriptors[Cnt]), - TaskgroupDescriptors[Cnt]->getExprLoc()); + llvm::Value *ReductionsPtr; + if (const Expr *TRExpr = TaskgroupDescriptors[Cnt]) { + ReductionsPtr = CGF.EmitLoadOfScalar(CGF.EmitLValue(TRExpr), + TRExpr->getExprLoc()); + } else { + ReductionsPtr = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); + } Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem( CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); Replacement = Address( diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 1f06514a38c13..024fc068c217c 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -848,55 +848,54 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass) SanOpts.Mask &= ~SanitizerKind::Null; - if (D) { - // Apply xray attributes to the function (as a string, for now) - if (const auto *XRayAttr = D->getAttr()) { - if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has( - XRayInstrKind::FunctionEntry) || - CGM.getCodeGenOpts().XRayInstrumentationBundle.has( - XRayInstrKind::FunctionExit)) { - if (XRayAttr->alwaysXRayInstrument() && ShouldXRayInstrumentFunction()) - Fn->addFnAttr("function-instrument", "xray-always"); - if (XRayAttr->neverXRayInstrument()) - Fn->addFnAttr("function-instrument", "xray-never"); - if (const auto *LogArgs = D->getAttr()) - if (ShouldXRayInstrumentFunction()) - Fn->addFnAttr("xray-log-args", - llvm::utostr(LogArgs->getArgumentCount())); - } - } else { - if (ShouldXRayInstrumentFunction() && !CGM.imbueXRayAttrs(Fn, Loc)) - Fn->addFnAttr( - "xray-instruction-threshold", - llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); + // Apply xray attributes to the function (as a string, for now) + if (const auto *XRayAttr = D ? D->getAttr() : nullptr) { + if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has( + XRayInstrKind::FunctionEntry) || + CGM.getCodeGenOpts().XRayInstrumentationBundle.has( + XRayInstrKind::FunctionExit)) { + if (XRayAttr->alwaysXRayInstrument() && ShouldXRayInstrumentFunction()) + Fn->addFnAttr("function-instrument", "xray-always"); + if (XRayAttr->neverXRayInstrument()) + Fn->addFnAttr("function-instrument", "xray-never"); + if (const auto *LogArgs = D->getAttr()) + if (ShouldXRayInstrumentFunction()) + Fn->addFnAttr("xray-log-args", + llvm::utostr(LogArgs->getArgumentCount())); } + } else { + if (ShouldXRayInstrumentFunction() && !CGM.imbueXRayAttrs(Fn, Loc)) + Fn->addFnAttr( + "xray-instruction-threshold", + llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); + } - if (ShouldXRayInstrumentFunction()) { - if (CGM.getCodeGenOpts().XRayIgnoreLoops) - Fn->addFnAttr("xray-ignore-loops"); + if (ShouldXRayInstrumentFunction()) { + if (CGM.getCodeGenOpts().XRayIgnoreLoops) + Fn->addFnAttr("xray-ignore-loops"); - if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has( - XRayInstrKind::FunctionExit)) - Fn->addFnAttr("xray-skip-exit"); + if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has( + XRayInstrKind::FunctionExit)) + Fn->addFnAttr("xray-skip-exit"); - if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has( - XRayInstrKind::FunctionEntry)) - Fn->addFnAttr("xray-skip-entry"); - } + if (!CGM.getCodeGenOpts().XRayInstrumentationBundle.has( + XRayInstrKind::FunctionEntry)) + Fn->addFnAttr("xray-skip-entry"); + } - unsigned Count, Offset; - if (const auto *Attr = D->getAttr()) { - Count = Attr->getCount(); - Offset = Attr->getOffset(); - } else { - Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount; - Offset = CGM.getCodeGenOpts().PatchableFunctionEntryOffset; - } - if (Count && Offset <= Count) { - Fn->addFnAttr("patchable-function-entry", std::to_string(Count - Offset)); - if (Offset) - Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset)); - } + unsigned Count, Offset; + if (const auto *Attr = + D ? D->getAttr() : nullptr) { + Count = Attr->getCount(); + Offset = Attr->getOffset(); + } else { + Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount; + Offset = CGM.getCodeGenOpts().PatchableFunctionEntryOffset; + } + if (Count && Offset <= Count) { + Fn->addFnAttr("patchable-function-entry", std::to_string(Count - Offset)); + if (Offset) + Fn->addFnAttr("patchable-function-prefix", std::to_string(Offset)); } // Add no-jump-tables value. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index cef4a6751491a..82a1f935e00a1 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -748,6 +748,19 @@ llvm::MDNode *CodeGenModule::getTBAATypeInfo(QualType QTy) { TBAAAccessInfo CodeGenModule::getTBAAAccessInfo(QualType AccessType) { if (!TBAA) return TBAAAccessInfo(); + if (getLangOpts().CUDAIsDevice) { + // As CUDA builtin surface/texture types are replaced, skip generating TBAA + // access info. + if (AccessType->isCUDADeviceBuiltinSurfaceType()) { + if (getTargetCodeGenInfo().getCUDADeviceBuiltinSurfaceDeviceType() != + nullptr) + return TBAAAccessInfo(); + } else if (AccessType->isCUDADeviceBuiltinTextureType()) { + if (getTargetCodeGenInfo().getCUDADeviceBuiltinTextureDeviceType() != + nullptr) + return TBAAAccessInfo(); + } + } return TBAA->getAccessInfo(AccessType); } @@ -2542,7 +2555,9 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { !Global->hasAttr() && !Global->hasAttr() && !Global->hasAttr() && - !(LangOpts.HIP && Global->hasAttr())) + !(LangOpts.HIP && Global->hasAttr()) && + !Global->getType()->isCUDADeviceBuiltinSurfaceType() && + !Global->getType()->isCUDADeviceBuiltinTextureType()) return; } else { // We need to emit host-side 'shadows' for all global @@ -2640,11 +2655,6 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { return; } - // Check if this must be emitted as declare variant. - if (LangOpts.OpenMP && isa(Global) && OpenMPRuntime && - OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/false)) - return; - // If we're deferring emission of a C++ variable with an // initializer, remember the order in which it appeared in the file. if (getLangOpts().CPlusPlus && isa(Global) && @@ -2850,50 +2860,6 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD, EmitGlobalFunctionDefinition(GD, GV); } -void CodeGenModule::emitOpenMPDeviceFunctionRedefinition( - GlobalDecl OldGD, GlobalDecl NewGD, llvm::GlobalValue *GV) { - assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && - OpenMPRuntime && "Expected OpenMP device mode."); - const auto *D = cast(OldGD.getDecl()); - - // Compute the function info and LLVM type. - const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(OldGD); - llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); - - // Get or create the prototype for the function. - if (!GV || (GV->getType()->getElementType() != Ty)) { - GV = cast(GetOrCreateLLVMFunction( - getMangledName(OldGD), Ty, GlobalDecl(), /*ForVTable=*/false, - /*DontDefer=*/true, /*IsThunk=*/false, llvm::AttributeList(), - ForDefinition)); - SetFunctionAttributes(OldGD, cast(GV), - /*IsIncompleteFunction=*/false, - /*IsThunk=*/false); - } - // We need to set linkage and visibility on the function before - // generating code for it because various parts of IR generation - // want to propagate this information down (e.g. to local static - // declarations). - auto *Fn = cast(GV); - setFunctionLinkage(OldGD, Fn); - - // FIXME: this is redundant with part of - // setFunctionDefinitionAttributes - setGVProperties(Fn, OldGD); - - MaybeHandleStaticInExternC(D, Fn); - - maybeSetTrivialComdat(*D, *Fn); - - CodeGenFunction(*this).GenerateCode(NewGD, Fn, FI); - - setNonAliasAttributes(OldGD, Fn); - SetLLVMFunctionAttributesForDefinition(D, Fn); - - if (D->hasAttr()) - AddGlobalAnnotations(D, Fn); -} - void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast(GD.getDecl()); @@ -3208,10 +3174,6 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( EmitGlobal(GDDef); } } - // Check if this must be emitted as declare variant and emit reference to - // the the declare variant function. - if (LangOpts.OpenMP && OpenMPRuntime) - (void)OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true); if (FD->isMultiVersion()) { if (FD->hasAttr()) @@ -4154,12 +4116,16 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, !getLangOpts().CUDAIsDevice && (D->hasAttr() || D->hasAttr() || D->hasAttr()); + bool IsCUDADeviceShadowVar = + getLangOpts().CUDAIsDevice && + (D->getType()->isCUDADeviceBuiltinSurfaceType() || + D->getType()->isCUDADeviceBuiltinTextureType()); // HIP pinned shadow of initialized host-side global variables are also // left undefined. bool IsHIPPinnedShadowVar = getLangOpts().CUDAIsDevice && D->hasAttr(); - if (getLangOpts().CUDA && - (IsCUDASharedVar || IsCUDAShadowVar || IsHIPPinnedShadowVar)) + if (getLangOpts().CUDA && (IsCUDASharedVar || IsCUDAShadowVar || + IsCUDADeviceShadowVar || IsHIPPinnedShadowVar)) Init = llvm::UndefValue::get(getTypes().ConvertType(ASTTy)); else if (D->hasAttr()) Init = llvm::UndefValue::get(getTypes().ConvertType(ASTTy)); @@ -4285,25 +4251,48 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (D->hasAttr() || D->hasAttr() || D->hasAttr()) { Linkage = llvm::GlobalValue::InternalLinkage; - - // Shadow variables and their properties must be registered - // with CUDA runtime. - unsigned Flags = 0; - if (!D->hasDefinition()) - Flags |= CGCUDARuntime::ExternDeviceVar; - if (D->hasAttr()) - Flags |= CGCUDARuntime::ConstantDeviceVar; - // Extern global variables will be registered in the TU where they are - // defined. + // Shadow variables and their properties must be registered with CUDA + // runtime. Skip Extern global variables, which will be registered in + // the TU where they are defined. if (!D->hasExternalStorage()) - getCUDARuntime().registerDeviceVar(D, *GV, Flags); - } else if (D->hasAttr()) + getCUDARuntime().registerDeviceVar(D, *GV, !D->hasDefinition(), + D->hasAttr()); + } else if (D->hasAttr()) { // __shared__ variables are odd. Shadows do get created, but // they are not registered with the CUDA runtime, so they // can't really be used to access their device-side // counterparts. It's not clear yet whether it's nvcc's bug or // a feature, but we've got to do the same for compatibility. Linkage = llvm::GlobalValue::InternalLinkage; + } else if (D->getType()->isCUDADeviceBuiltinSurfaceType() || + D->getType()->isCUDADeviceBuiltinTextureType()) { + // Builtin surfaces and textures and their template arguments are + // also registered with CUDA runtime. + Linkage = llvm::GlobalValue::InternalLinkage; + const ClassTemplateSpecializationDecl *TD = + cast( + D->getType()->getAs()->getDecl()); + const TemplateArgumentList &Args = TD->getTemplateArgs(); + if (TD->hasAttr()) { + assert(Args.size() == 2 && + "Unexpected number of template arguments of CUDA device " + "builtin surface type."); + auto SurfType = Args[1].getAsIntegral(); + if (!D->hasExternalStorage()) + getCUDARuntime().registerDeviceSurf(D, *GV, !D->hasDefinition(), + SurfType.getSExtValue()); + } else { + assert(Args.size() == 3 && + "Unexpected number of template arguments of CUDA device " + "builtin texture type."); + auto TexType = Args[1].getAsIntegral(); + auto Normalized = Args[2].getAsIntegral(); + if (!D->hasExternalStorage()) + getCUDARuntime().registerDeviceTex(D, *GV, !D->hasDefinition(), + TexType.getSExtValue(), + Normalized.getZExtValue()); + } + } } } @@ -4688,11 +4677,6 @@ void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { - // Check if this must be emitted as declare variant. - if (LangOpts.OpenMP && OpenMPRuntime && - OpenMPRuntime->emitDeclareVariant(GD, /*IsForDefinition=*/true)) - return; - const auto *D = cast(GD.getDecl()); // Compute the function info and LLVM type. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index a538884a97f6e..4565b924ae27a 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1310,11 +1310,6 @@ class CodeGenModule : public CodeGenTypeCache { /// \param D Requires declaration void EmitOMPRequiresDecl(const OMPRequiresDecl *D); - /// Emits the definition of \p OldGD function with body from \p NewGD. - /// Required for proper handling of declare variant directive on the GPU. - void emitOpenMPDeviceFunctionRedefinition(GlobalDecl OldGD, GlobalDecl NewGD, - llvm::GlobalValue *GV); - /// Returns whether the given record has hidden LTO visibility and therefore /// may participate in (single-module) CFI and whole-program vtable /// optimization. diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 7d730cb1ed154..8cc8c162dfbe7 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -141,6 +141,34 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) { case BuiltinType::UInt128: return getTypeInfo(Context.Int128Ty); + case BuiltinType::UShortFract: + return getTypeInfo(Context.ShortFractTy); + case BuiltinType::UFract: + return getTypeInfo(Context.FractTy); + case BuiltinType::ULongFract: + return getTypeInfo(Context.LongFractTy); + + case BuiltinType::SatUShortFract: + return getTypeInfo(Context.SatShortFractTy); + case BuiltinType::SatUFract: + return getTypeInfo(Context.SatFractTy); + case BuiltinType::SatULongFract: + return getTypeInfo(Context.SatLongFractTy); + + case BuiltinType::UShortAccum: + return getTypeInfo(Context.ShortAccumTy); + case BuiltinType::UAccum: + return getTypeInfo(Context.AccumTy); + case BuiltinType::ULongAccum: + return getTypeInfo(Context.LongAccumTy); + + case BuiltinType::SatUShortAccum: + return getTypeInfo(Context.SatShortAccumTy); + case BuiltinType::SatUAccum: + return getTypeInfo(Context.SatAccumTy); + case BuiltinType::SatULongAccum: + return getTypeInfo(Context.SatLongAccumTy); + // Treat all other builtin types as distinct types. This includes // treating wchar_t, char16_t, and char32_t as distinct from their // "underlying types". diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index aa32d83de0af0..caa71b10f2311 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -397,6 +397,20 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { const Type *Ty = T.getTypePtr(); + // For the device-side compilation, CUDA device builtin surface/texture types + // may be represented in different types. + if (Context.getLangOpts().CUDAIsDevice) { + if (T->isCUDADeviceBuiltinSurfaceType()) { + if (auto *Ty = CGM.getTargetCodeGenInfo() + .getCUDADeviceBuiltinSurfaceDeviceType()) + return Ty; + } else if (T->isCUDADeviceBuiltinTextureType()) { + if (auto *Ty = CGM.getTargetCodeGenInfo() + .getCUDADeviceBuiltinTextureDeviceType()) + return Ty; + } + } + // RecordTypes are cached and processed specially. if (const RecordType *RT = dyn_cast(Ty)) return ConvertRecordDeclType(RT->getDecl()); @@ -595,7 +609,11 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { llvm::Type *PointeeType = ConvertTypeForMem(ETy); if (PointeeType->isVoidTy()) PointeeType = llvm::Type::getInt8Ty(getLLVMContext()); - unsigned AS = Context.getTargetAddressSpace(ETy); + + unsigned AS = PointeeType->isFunctionTy() + ? getDataLayout().getProgramAddressSpace() + : Context.getTargetAddressSpace(ETy); + ResultType = llvm::PointerType::get(PointeeType, AS); break; } diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 9033853d619f7..24c102acd98d4 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/IntrinsicsNVPTX.h" #include "llvm/IR/Type.h" #include "llvm/Support/raw_ostream.h" #include // std::sort @@ -5106,9 +5107,11 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo { if (!FD) return; - CodeGenOptions::SignReturnAddressScope Scope = CGM.getCodeGenOpts().getSignReturnAddress(); - CodeGenOptions::SignReturnAddressKeyValue Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); - bool BranchTargetEnforcement = CGM.getCodeGenOpts().BranchTargetEnforcement; + LangOptions::SignReturnAddressScopeKind Scope = + CGM.getLangOpts().getSignReturnAddressScope(); + LangOptions::SignReturnAddressKeyKind Key = + CGM.getLangOpts().getSignReturnAddressKey(); + bool BranchTargetEnforcement = CGM.getLangOpts().BranchTargetEnforcement; if (const auto *TA = FD->getAttr()) { ParsedTargetAttr Attr = TA->parse(); if (!Attr.BranchProtection.empty()) { @@ -5124,14 +5127,14 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo { } auto *Fn = cast(GV); - if (Scope != CodeGenOptions::SignReturnAddressScope::None) { + if (Scope != LangOptions::SignReturnAddressScopeKind::None) { Fn->addFnAttr("sign-return-address", - Scope == CodeGenOptions::SignReturnAddressScope::All + Scope == LangOptions::SignReturnAddressScopeKind::All ? "all" : "non-leaf"); Fn->addFnAttr("sign-return-address-key", - Key == CodeGenOptions::SignReturnAddressKeyValue::AKey + Key == LangOptions::SignReturnAddressKeyKind::AKey ? "a_key" : "b_key"); } @@ -6414,9 +6417,14 @@ Address ARMABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, namespace { +class NVPTXTargetCodeGenInfo; + class NVPTXABIInfo : public ABIInfo { + NVPTXTargetCodeGenInfo &CGInfo; + public: - NVPTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + NVPTXABIInfo(CodeGenTypes &CGT, NVPTXTargetCodeGenInfo &Info) + : ABIInfo(CGT), CGInfo(Info) {} ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType Ty) const; @@ -6429,16 +6437,61 @@ class NVPTXABIInfo : public ABIInfo { class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo { public: NVPTXTargetCodeGenInfo(CodeGenTypes &CGT) - : TargetCodeGenInfo(new NVPTXABIInfo(CGT)) {} + : TargetCodeGenInfo(new NVPTXABIInfo(CGT, *this)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const override; bool shouldEmitStaticExternCAliases() const override; + llvm::Type *getCUDADeviceBuiltinSurfaceDeviceType() const override { + // On the device side, surface reference is represented as an object handle + // in 64-bit integer. + return llvm::Type::getInt64Ty(getABIInfo().getVMContext()); + } + + llvm::Type *getCUDADeviceBuiltinTextureDeviceType() const override { + // On the device side, texture reference is represented as an object handle + // in 64-bit integer. + return llvm::Type::getInt64Ty(getABIInfo().getVMContext()); + } + + bool emitCUDADeviceBuiltinSurfaceDeviceCopy(CodeGenFunction &CGF, LValue Dst, + LValue Src) const override { + emitBuiltinSurfTexDeviceCopy(CGF, Dst, Src); + return true; + } + + bool emitCUDADeviceBuiltinTextureDeviceCopy(CodeGenFunction &CGF, LValue Dst, + LValue Src) const override { + emitBuiltinSurfTexDeviceCopy(CGF, Dst, Src); + return true; + } + private: - // Adds a NamedMDNode with F, Name, and Operand as operands, and adds the + // Adds a NamedMDNode with GV, Name, and Operand as operands, and adds the // resulting MDNode to the nvvm.annotations MDNode. - static void addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand); + static void addNVVMMetadata(llvm::GlobalValue *GV, StringRef Name, + int Operand); + + static void emitBuiltinSurfTexDeviceCopy(CodeGenFunction &CGF, LValue Dst, + LValue Src) { + llvm::Value *Handle = nullptr; + llvm::Constant *C = + llvm::dyn_cast(Src.getAddress(CGF).getPointer()); + // Lookup `addrspacecast` through the constant pointer if any. + if (auto *ASC = llvm::dyn_cast_or_null(C)) + C = llvm::cast(ASC->getPointerOperand()); + if (auto *GV = llvm::dyn_cast_or_null(C)) { + // Load the handle from the specific global variable using + // `nvvm.texsurf.handle.internal` intrinsic. + Handle = CGF.EmitRuntimeCall( + CGF.CGM.getIntrinsic(llvm::Intrinsic::nvvm_texsurf_handle_internal, + {GV->getType()}), + {GV}, "texsurf_handle"); + } else + Handle = CGF.EmitLoadOfScalar(Src, SourceLocation()); + CGF.EmitStoreOfScalar(Handle, Dst); + } }; /// Checks if the type is unsupported directly by the current target. @@ -6511,8 +6564,19 @@ ABIArgInfo NVPTXABIInfo::classifyArgumentType(QualType Ty) const { Ty = EnumTy->getDecl()->getIntegerType(); // Return aggregates type as indirect by value - if (isAggregateTypeForABI(Ty)) + if (isAggregateTypeForABI(Ty)) { + // Under CUDA device compilation, tex/surf builtin types are replaced with + // object types and passed directly. + if (getContext().getLangOpts().CUDAIsDevice) { + if (Ty->isCUDADeviceBuiltinSurfaceType()) + return ABIArgInfo::getDirect( + CGInfo.getCUDADeviceBuiltinSurfaceDeviceType()); + if (Ty->isCUDADeviceBuiltinTextureType()) + return ABIArgInfo::getDirect( + CGInfo.getCUDADeviceBuiltinTextureDeviceType()); + } return getNaturalAlignIndirect(Ty, /* byval */ true); + } return (Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); @@ -6540,6 +6604,17 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes( const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { if (GV->isDeclaration()) return; + const VarDecl *VD = dyn_cast_or_null(D); + if (VD) { + if (M.getLangOpts().CUDA) { + if (VD->getType()->isCUDADeviceBuiltinSurfaceType()) + addNVVMMetadata(GV, "surface", 1); + else if (VD->getType()->isCUDADeviceBuiltinTextureType()) + addNVVMMetadata(GV, "texture", 1); + return; + } + } + const FunctionDecl *FD = dyn_cast_or_null(D); if (!FD) return; @@ -6588,16 +6663,16 @@ void NVPTXTargetCodeGenInfo::setTargetAttributes( } } -void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::Function *F, StringRef Name, - int Operand) { - llvm::Module *M = F->getParent(); +void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV, + StringRef Name, int Operand) { + llvm::Module *M = GV->getParent(); llvm::LLVMContext &Ctx = M->getContext(); // Get "nvvm.annotations" metadata node llvm::NamedMDNode *MD = M->getOrInsertNamedMetadata("nvvm.annotations"); llvm::Metadata *MDVals[] = { - llvm::ConstantAsMetadata::get(F), llvm::MDString::get(Ctx, Name), + llvm::ConstantAsMetadata::get(GV), llvm::MDString::get(Ctx, Name), llvm::ConstantAsMetadata::get( llvm::ConstantInt::get(llvm::Type::getInt32Ty(Ctx), Operand))}; // Append metadata to nvvm.annotations @@ -7511,18 +7586,25 @@ void TCETargetCodeGenInfo::setTargetAttributes( namespace { -class HexagonABIInfo : public ABIInfo { +class HexagonABIInfo : public DefaultABIInfo { public: - HexagonABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + HexagonABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} private: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy, unsigned *RegsLeft) const; void computeInfo(CGFunctionInfo &FI) const override; Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const override; + Address EmitVAArgFromMemory(CodeGenFunction &CFG, Address VAListAddr, + QualType Ty) const; + Address EmitVAArgForHexagon(CodeGenFunction &CFG, Address VAListAddr, + QualType Ty) const; + Address EmitVAArgForHexagonLinux(CodeGenFunction &CFG, Address VAListAddr, + QualType Ty) const; }; class HexagonTargetCodeGenInfo : public TargetCodeGenInfo { @@ -7533,23 +7615,63 @@ class HexagonTargetCodeGenInfo : public TargetCodeGenInfo { int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { return 29; } + + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &GCM) const override { + if (GV->isDeclaration()) + return; + const FunctionDecl *FD = dyn_cast_or_null(D); + if (!FD) + return; + } }; } // namespace void HexagonABIInfo::computeInfo(CGFunctionInfo &FI) const { + unsigned RegsLeft = 6; if (!getCXXABI().classifyReturnType(FI)) FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (auto &I : FI.arguments()) - I.info = classifyArgumentType(I.type); + I.info = classifyArgumentType(I.type, &RegsLeft); +} + +static bool HexagonAdjustRegsLeft(uint64_t Size, unsigned *RegsLeft) { + assert(Size <= 64 && "Not expecting to pass arguments larger than 64 bits" + " through registers"); + + if (*RegsLeft == 0) + return false; + + if (Size <= 32) { + (*RegsLeft)--; + return true; + } + + if (2 <= (*RegsLeft & (~1U))) { + *RegsLeft = (*RegsLeft & (~1U)) - 2; + return true; + } + + // Next available register was r5 but candidate was greater than 32-bits so it + // has to go on the stack. However we still consume r5 + if (*RegsLeft == 1) + *RegsLeft = 0; + + return false; } -ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const { +ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty, + unsigned *RegsLeft) const { if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); + uint64_t Size = getContext().getTypeSize(Ty); + if (Size <= 64) + HexagonAdjustRegsLeft(Size, RegsLeft); + return Ty->isPromotableIntegerType() ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect(); } @@ -7562,13 +7684,20 @@ ABIArgInfo HexagonABIInfo::classifyArgumentType(QualType Ty) const { return ABIArgInfo::getIgnore(); uint64_t Size = getContext().getTypeSize(Ty); - if (Size <= 64) { + unsigned Align = getContext().getTypeAlign(Ty); + + if (Size > 64) + return getNaturalAlignIndirect(Ty, /*ByVal=*/true); + + if (HexagonAdjustRegsLeft(Size, RegsLeft)) + Align = Size <= 32 ? 32 : 64; + if (Size <= Align) { // Pass in the smallest viable integer type. if (!llvm::isPowerOf2_64(Size)) Size = llvm::NextPowerOf2(Size); return ABIArgInfo::getDirect(llvm::Type::getIntNTy(getVMContext(), Size)); } - return getNaturalAlignIndirect(Ty, /*ByVal=*/true); + return DefaultABIInfo::classifyArgumentType(Ty); } ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { @@ -7586,7 +7715,6 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { if (Size == VecSize || Size == 2*VecSize) return ABIArgInfo::getDirectInReg(); } - // Large vector types should be returned via memory. if (Size > 64) return getNaturalAlignIndirect(RetTy); @@ -7615,13 +7743,242 @@ ABIArgInfo HexagonABIInfo::classifyReturnType(QualType RetTy) const { return getNaturalAlignIndirect(RetTy, /*ByVal=*/true); } +Address HexagonABIInfo::EmitVAArgFromMemory(CodeGenFunction &CGF, + Address VAListAddr, + QualType Ty) const { + // Load the overflow area pointer. + Address __overflow_area_pointer_p = + CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p"); + llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad( + __overflow_area_pointer_p, "__overflow_area_pointer"); + + uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8; + if (Align > 4) { + // Alignment should be a power of 2. + assert((Align & (Align - 1)) == 0 && "Alignment is not power of 2!"); + + // overflow_arg_area = (overflow_arg_area + align - 1) & -align; + llvm::Value *Offset = llvm::ConstantInt::get(CGF.Int64Ty, Align - 1); + + // Add offset to the current pointer to access the argument. + __overflow_area_pointer = + CGF.Builder.CreateGEP(__overflow_area_pointer, Offset); + llvm::Value *AsInt = + CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty); + + // Create a mask which should be "AND"ed + // with (overflow_arg_area + align - 1) + llvm::Value *Mask = llvm::ConstantInt::get(CGF.Int32Ty, -(int)Align); + __overflow_area_pointer = CGF.Builder.CreateIntToPtr( + CGF.Builder.CreateAnd(AsInt, Mask), __overflow_area_pointer->getType(), + "__overflow_area_pointer.align"); + } + + // Get the type of the argument from memory and bitcast + // overflow area pointer to the argument type. + llvm::Type *PTy = CGF.ConvertTypeForMem(Ty); + Address AddrTyped = CGF.Builder.CreateBitCast( + Address(__overflow_area_pointer, CharUnits::fromQuantity(Align)), + llvm::PointerType::getUnqual(PTy)); + + // Round up to the minimum stack alignment for varargs which is 4 bytes. + uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4); + + __overflow_area_pointer = CGF.Builder.CreateGEP( + __overflow_area_pointer, llvm::ConstantInt::get(CGF.Int32Ty, Offset), + "__overflow_area_pointer.next"); + CGF.Builder.CreateStore(__overflow_area_pointer, __overflow_area_pointer_p); + + return AddrTyped; +} + +Address HexagonABIInfo::EmitVAArgForHexagon(CodeGenFunction &CGF, + Address VAListAddr, + QualType Ty) const { + // FIXME: Need to handle alignment + llvm::Type *BP = CGF.Int8PtrTy; + llvm::Type *BPP = CGF.Int8PtrPtrTy; + CGBuilderTy &Builder = CGF.Builder; + Address VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + // Handle address alignment for type alignment > 32 bits + uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8; + if (TyAlign > 4) { + assert((TyAlign & (TyAlign - 1)) == 0 && "Alignment is not power of 2!"); + llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty); + AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1)); + AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1))); + Addr = Builder.CreateIntToPtr(AddrAsInt, BP); + } + llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + Address AddrTyped = Builder.CreateBitCast( + Address(Addr, CharUnits::fromQuantity(TyAlign)), PTy); + + uint64_t Offset = llvm::alignTo(CGF.getContext().getTypeSize(Ty) / 8, 4); + llvm::Value *NextAddr = Builder.CreateGEP( + Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; +} + +Address HexagonABIInfo::EmitVAArgForHexagonLinux(CodeGenFunction &CGF, + Address VAListAddr, + QualType Ty) const { + int ArgSize = CGF.getContext().getTypeSize(Ty) / 8; + + if (ArgSize > 8) + return EmitVAArgFromMemory(CGF, VAListAddr, Ty); + + // Here we have check if the argument is in register area or + // in overflow area. + // If the saved register area pointer + argsize rounded up to alignment > + // saved register area end pointer, argument is in overflow area. + unsigned RegsLeft = 6; + Ty = CGF.getContext().getCanonicalType(Ty); + (void)classifyArgumentType(Ty, &RegsLeft); + + llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg"); + llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); + llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack"); + llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); + + // Get rounded size of the argument.GCC does not allow vararg of + // size < 4 bytes. We follow the same logic here. + ArgSize = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8; + int ArgAlign = (CGF.getContext().getTypeSize(Ty) <= 32) ? 4 : 8; + + // Argument may be in saved register area + CGF.EmitBlock(MaybeRegBlock); + + // Load the current saved register area pointer. + Address __current_saved_reg_area_pointer_p = CGF.Builder.CreateStructGEP( + VAListAddr, 0, "__current_saved_reg_area_pointer_p"); + llvm::Value *__current_saved_reg_area_pointer = CGF.Builder.CreateLoad( + __current_saved_reg_area_pointer_p, "__current_saved_reg_area_pointer"); + + // Load the saved register area end pointer. + Address __saved_reg_area_end_pointer_p = CGF.Builder.CreateStructGEP( + VAListAddr, 1, "__saved_reg_area_end_pointer_p"); + llvm::Value *__saved_reg_area_end_pointer = CGF.Builder.CreateLoad( + __saved_reg_area_end_pointer_p, "__saved_reg_area_end_pointer"); + + // If the size of argument is > 4 bytes, check if the stack + // location is aligned to 8 bytes + if (ArgAlign > 4) { + + llvm::Value *__current_saved_reg_area_pointer_int = + CGF.Builder.CreatePtrToInt(__current_saved_reg_area_pointer, + CGF.Int32Ty); + + __current_saved_reg_area_pointer_int = CGF.Builder.CreateAdd( + __current_saved_reg_area_pointer_int, + llvm::ConstantInt::get(CGF.Int32Ty, (ArgAlign - 1)), + "align_current_saved_reg_area_pointer"); + + __current_saved_reg_area_pointer_int = + CGF.Builder.CreateAnd(__current_saved_reg_area_pointer_int, + llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign), + "align_current_saved_reg_area_pointer"); + + __current_saved_reg_area_pointer = + CGF.Builder.CreateIntToPtr(__current_saved_reg_area_pointer_int, + __current_saved_reg_area_pointer->getType(), + "align_current_saved_reg_area_pointer"); + } + + llvm::Value *__new_saved_reg_area_pointer = + CGF.Builder.CreateGEP(__current_saved_reg_area_pointer, + llvm::ConstantInt::get(CGF.Int32Ty, ArgSize), + "__new_saved_reg_area_pointer"); + + llvm::Value *UsingStack = 0; + UsingStack = CGF.Builder.CreateICmpSGT(__new_saved_reg_area_pointer, + __saved_reg_area_end_pointer); + + CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, InRegBlock); + + // Argument in saved register area + // Implement the block where argument is in register saved area + CGF.EmitBlock(InRegBlock); + + llvm::Type *PTy = CGF.ConvertType(Ty); + llvm::Value *__saved_reg_area_p = CGF.Builder.CreateBitCast( + __current_saved_reg_area_pointer, llvm::PointerType::getUnqual(PTy)); + + CGF.Builder.CreateStore(__new_saved_reg_area_pointer, + __current_saved_reg_area_pointer_p); + + CGF.EmitBranch(ContBlock); + + // Argument in overflow area + // Implement the block where the argument is in overflow area. + CGF.EmitBlock(OnStackBlock); + + // Load the overflow area pointer + Address __overflow_area_pointer_p = + CGF.Builder.CreateStructGEP(VAListAddr, 2, "__overflow_area_pointer_p"); + llvm::Value *__overflow_area_pointer = CGF.Builder.CreateLoad( + __overflow_area_pointer_p, "__overflow_area_pointer"); + + // Align the overflow area pointer according to the alignment of the argument + if (ArgAlign > 4) { + llvm::Value *__overflow_area_pointer_int = + CGF.Builder.CreatePtrToInt(__overflow_area_pointer, CGF.Int32Ty); + + __overflow_area_pointer_int = + CGF.Builder.CreateAdd(__overflow_area_pointer_int, + llvm::ConstantInt::get(CGF.Int32Ty, ArgAlign - 1), + "align_overflow_area_pointer"); + + __overflow_area_pointer_int = + CGF.Builder.CreateAnd(__overflow_area_pointer_int, + llvm::ConstantInt::get(CGF.Int32Ty, -ArgAlign), + "align_overflow_area_pointer"); + + __overflow_area_pointer = CGF.Builder.CreateIntToPtr( + __overflow_area_pointer_int, __overflow_area_pointer->getType(), + "align_overflow_area_pointer"); + } + + // Get the pointer for next argument in overflow area and store it + // to overflow area pointer. + llvm::Value *__new_overflow_area_pointer = CGF.Builder.CreateGEP( + __overflow_area_pointer, llvm::ConstantInt::get(CGF.Int32Ty, ArgSize), + "__overflow_area_pointer.next"); + + CGF.Builder.CreateStore(__new_overflow_area_pointer, + __overflow_area_pointer_p); + + CGF.Builder.CreateStore(__new_overflow_area_pointer, + __current_saved_reg_area_pointer_p); + + // Bitcast the overflow area pointer to the type of argument. + llvm::Type *OverflowPTy = CGF.ConvertTypeForMem(Ty); + llvm::Value *__overflow_area_p = CGF.Builder.CreateBitCast( + __overflow_area_pointer, llvm::PointerType::getUnqual(OverflowPTy)); + + CGF.EmitBranch(ContBlock); + + // Get the correct pointer to load the variable argument + // Implement the ContBlock + CGF.EmitBlock(ContBlock); + + llvm::Type *MemPTy = llvm::PointerType::getUnqual(CGF.ConvertTypeForMem(Ty)); + llvm::PHINode *ArgAddr = CGF.Builder.CreatePHI(MemPTy, 2, "vaarg.addr"); + ArgAddr->addIncoming(__saved_reg_area_p, InRegBlock); + ArgAddr->addIncoming(__overflow_area_p, OnStackBlock); + + return Address(ArgAddr, CharUnits::fromQuantity(ArgAlign)); +} + Address HexagonABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { - // FIXME: Someone needs to audit that this handle alignment correctly. - return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, - getContext().getTypeInfoInChars(Ty), - CharUnits::fromQuantity(4), - /*AllowHigherAlign*/ true); + + if (getTarget().getTriple().isMusl()) + return EmitVAArgForHexagonLinux(CGF, VAListAddr, Ty); + + return EmitVAArgForHexagon(CGF, VAListAddr, Ty); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index e1e90e73cb587..e7c842bae4a98 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -315,6 +315,32 @@ class TargetCodeGenInfo { virtual bool shouldEmitStaticExternCAliases() const { return true; } virtual void setCUDAKernelCallingConvention(const FunctionType *&FT) const {} + + /// Return the device-side type for the CUDA device builtin surface type. + virtual llvm::Type *getCUDADeviceBuiltinSurfaceDeviceType() const { + // By default, no change from the original one. + return nullptr; + } + /// Return the device-side type for the CUDA device builtin texture type. + virtual llvm::Type *getCUDADeviceBuiltinTextureDeviceType() const { + // By default, no change from the original one. + return nullptr; + } + + /// Emit the device-side copy of the builtin surface type. + virtual bool emitCUDADeviceBuiltinSurfaceDeviceCopy(CodeGenFunction &CGF, + LValue Dst, + LValue Src) const { + // DO NOTHING by default. + return false; + } + /// Emit the device-side copy of the builtin texture type. + virtual bool emitCUDADeviceBuiltinTextureDeviceCopy(CodeGenFunction &CGF, + LValue Dst, + LValue Src) const { + // DO NOTHING by default. + return false; + } }; } // namespace CodeGen diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 31115e51dea16..029ba62b5209f 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -141,6 +141,13 @@ Driver::Driver(StringRef ClangExecutable, StringRef TargetTriple, Dir = std::string(llvm::sys::path::parent_path(ClangExecutable)); InstalledDir = Dir; // Provide a sensible default installed dir. + if ((!SysRoot.empty()) && llvm::sys::path::is_relative(SysRoot)) { + // Prepend InstalledDir if SysRoot is relative + SmallString<128> P(InstalledDir); + llvm::sys::path::append(P, SysRoot); + SysRoot = std::string(P); + } + #if defined(CLANG_CONFIG_FILE_SYSTEM_DIR) SystemConfigDir = CLANG_CONFIG_FILE_SYSTEM_DIR; #endif @@ -1454,10 +1461,6 @@ void Driver::generateCompilationDiagnostics( // Print the version of the compiler. PrintVersion(C, llvm::errs()); - Diag(clang::diag::note_drv_command_failed_diag_msg) - << "PLEASE submit a bug report to " BUG_REPORT_URL " and include the " - "crash backtrace, preprocessed source, and associated run script."; - // Suppress driver output and emit preprocessor output to temp file. Mode = CPPMode; CCGenDiagnostics = true; @@ -2976,13 +2979,13 @@ class OffloadingActionBuilder final { std::set GpuArchs; bool Error = false; for (Arg *A : Args) { - if (!(A->getOption().matches(options::OPT_cuda_gpu_arch_EQ) || - A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ))) + if (!(A->getOption().matches(options::OPT_offload_arch_EQ) || + A->getOption().matches(options::OPT_no_offload_arch_EQ))) continue; A->claim(); const StringRef ArchStr = A->getValue(); - if (A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ) && + if (A->getOption().matches(options::OPT_no_offload_arch_EQ) && ArchStr == "all") { GpuArchs.clear(); continue; @@ -2991,9 +2994,9 @@ class OffloadingActionBuilder final { if (Arch == CudaArch::UNKNOWN) { C.getDriver().Diag(clang::diag::err_drv_cuda_bad_gpu_arch) << ArchStr; Error = true; - } else if (A->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) + } else if (A->getOption().matches(options::OPT_offload_arch_EQ)) GpuArchs.insert(Arch); - else if (A->getOption().matches(options::OPT_no_cuda_gpu_arch_EQ)) + else if (A->getOption().matches(options::OPT_no_offload_arch_EQ)) GpuArchs.erase(Arch); else llvm_unreachable("Unexpected option."); @@ -3982,7 +3985,7 @@ class OffloadingActionBuilder final { A->claim(); auto ParsedArg = Opts.ParseOneArg(Args, Index); // TODO: Support --no-cuda-gpu-arch, --{,no-}cuda-gpu-arch=all. - if (ParsedArg->getOption().matches(options::OPT_cuda_gpu_arch_EQ)) { + if (ParsedArg->getOption().matches(options::OPT_offload_arch_EQ)) { ParsedArg->claim(); GpuArchList.push_back(StringToCudaArch(ParsedArg->getValue(0))); } diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 06e4686ac2b98..2cec0dc9de22c 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -103,6 +103,18 @@ AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, return DAL; } +bool AMDGPUToolChain::getDefaultDenormsAreZeroForTarget( + llvm::AMDGPU::GPUKind Kind) { + const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind); + + // Default to enabling f32 denormals by default on subtargets where fma is + // fast with denormals + const bool BothDenormAndFMAFast = + (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) && + (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32); + return !BothDenormAndFMAFast; +} + llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType( const llvm::opt::ArgList &DriverArgs, Action::OffloadKind DeviceOffloadKind, const llvm::fltSemantics *FPType) const { @@ -121,18 +133,10 @@ llvm::DenormalMode AMDGPUToolChain::getDefaultDenormalModeForType( const StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_mcpu_EQ); auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); - // Default to enabling f32 denormals by default on subtargets where fma is - // fast with denormals - - const unsigned ArchAttr = llvm::AMDGPU::getArchAttrAMDGCN(Kind); - const bool DefaultDenormsAreZeroForTarget = - (ArchAttr & llvm::AMDGPU::FEATURE_FAST_FMA_F32) && - (ArchAttr & llvm::AMDGPU::FEATURE_FAST_DENORMAL_F32); - // TODO: There are way too many flags that change this. Do we need to check // them all? bool DAZ = DriverArgs.hasArg(options::OPT_cl_denorms_are_zero) || - !DefaultDenormsAreZeroForTarget; + getDefaultDenormsAreZeroForTarget(Kind); // Outputs are flushed to zero, preserving sign return DAZ ? llvm::DenormalMode::getPreserveSign() : llvm::DenormalMode::getIEEE(); diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h index 78c40580b3020..e7a873efb0085 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -13,6 +13,8 @@ #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include "llvm/Support/TargetParser.h" + #include namespace clang { @@ -67,6 +69,10 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + /// Return whether denormals should be flushed, and treated as 0 by default + /// for the subtarget. + static bool getDefaultDenormsAreZeroForTarget(llvm::AMDGPU::GPUKind GPUKind); + llvm::DenormalMode getDefaultDenormalModeForType( const llvm::opt::ArgList &DriverArgs, Action::OffloadKind DeviceOffloadKind, diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index dc31a5ab7b0f0..b21cfac6e7ed7 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -140,7 +140,8 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = std::string(llvm::sys::getHostCPUName()); - if (MtuneLowerCase == "cyclone" || MtuneLowerCase.find("apple") == 0) { + if (MtuneLowerCase == "cyclone" || + StringRef(MtuneLowerCase).startswith("apple")) { Features.push_back("+zcm"); Features.push_back("+zcz"); } diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index 4d871104c95ac..f81bf68172de1 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "SystemZ.h" +#include "clang/Config/config.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" @@ -47,7 +48,7 @@ std::string systemz::getSystemZTargetCPU(const ArgList &Args) { return std::string(CPUName); } - return "z10"; + return CLANG_SYSTEMZ_DEFAULT_ARCH; } void systemz::getSystemZTargetFeatures(const Driver &D, const ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 44a636dcfd1ce..dbbc025de38c0 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -146,6 +146,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, // flags). This is a bit hacky but keeps existing usages working. We should // consider deprecating this and instead warn if the user requests external // retpoline thunks and *doesn't* request some form of retpolines. + auto SpectreOpt = clang::driver::options::ID::OPT_INVALID; if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline, options::OPT_mspeculative_load_hardening, options::OPT_mno_speculative_load_hardening)) { @@ -153,12 +154,14 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, false)) { Features.push_back("+retpoline-indirect-calls"); Features.push_back("+retpoline-indirect-branches"); + SpectreOpt = options::OPT_mretpoline; } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening, options::OPT_mno_speculative_load_hardening, false)) { // On x86, speculative load hardening relies on at least using retpolines // for indirect calls. Features.push_back("+retpoline-indirect-calls"); + SpectreOpt = options::OPT_mspeculative_load_hardening; } } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk, options::OPT_mno_retpoline_external_thunk, false)) { @@ -166,6 +169,26 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, // eventually switch to an error here. Features.push_back("+retpoline-indirect-calls"); Features.push_back("+retpoline-indirect-branches"); + SpectreOpt = options::OPT_mretpoline_external_thunk; + } + + auto LVIOpt = clang::driver::options::ID::OPT_INVALID; + if (Args.hasFlag(options::OPT_mlvi_hardening, options::OPT_mno_lvi_hardening, + false)) { + Features.push_back("+lvi-load-hardening"); + Features.push_back("+lvi-cfi"); // load hardening implies CFI protection + LVIOpt = options::OPT_mlvi_hardening; + } else if (Args.hasFlag(options::OPT_mlvi_cfi, options::OPT_mno_lvi_cfi, + false)) { + Features.push_back("+lvi-cfi"); + LVIOpt = options::OPT_mlvi_cfi; + } + + if (SpectreOpt != clang::driver::options::ID::OPT_INVALID && + LVIOpt != clang::driver::options::ID::OPT_INVALID) { + D.Diag(diag::err_drv_argument_not_allowed_with) + << D.getOpts().getOptionName(SpectreOpt) + << D.getOpts().getOptionName(LVIOpt); } // Now add any that the user explicitly requested on the command line, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 12d5345a64af5..603d04f0a9b3d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3579,9 +3579,9 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, CmdArgs.push_back("-fno-diagnostics-fixit-info"); // Enable -fdiagnostics-show-option by default. - if (Args.hasFlag(options::OPT_fdiagnostics_show_option, - options::OPT_fno_diagnostics_show_option)) - CmdArgs.push_back("-fdiagnostics-show-option"); + if (!Args.hasFlag(options::OPT_fdiagnostics_show_option, + options::OPT_fno_diagnostics_show_option, true)) + CmdArgs.push_back("-fno-diagnostics-show-option"); if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { @@ -4273,7 +4273,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef ArgStr = Args.hasArg(options::OPT_interface_stub_version_EQ) ? Args.getLastArgValue(options::OPT_interface_stub_version_EQ) - : "experimental-ifs-v1"; + : "experimental-ifs-v2"; CmdArgs.push_back("-emit-interface-stubs"); CmdArgs.push_back( Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str())); @@ -4733,9 +4733,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. bool IsIntegratedAssemblerDefault = TC.IsIntegratedAssemblerDefault(); - if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, - IsIntegratedAssemblerDefault)) - CmdArgs.push_back("-masm-verbose"); + if (!Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, + IsIntegratedAssemblerDefault)) + CmdArgs.push_back("-fno-verbose-asm"); if (!TC.useIntegratedAs()) CmdArgs.push_back("-no-integrated-as"); @@ -5220,15 +5220,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Pass -fmessage-length=. - CmdArgs.push_back("-fmessage-length"); + unsigned MessageLength = 0; if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { - CmdArgs.push_back(A->getValue()); + StringRef V(A->getValue()); + if (V.getAsInteger(0, MessageLength)) + D.Diag(diag::err_drv_invalid_argument_to_option) + << V << A->getOption().getName(); } else { // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. - unsigned N = llvm::sys::Process::StandardErrColumns(); - CmdArgs.push_back(Args.MakeArgString(Twine(N))); + MessageLength = llvm::sys::Process::StandardErrColumns(); } + if (MessageLength != 0) + CmdArgs.push_back( + Args.MakeArgString("-fmessage-length=" + Twine(MessageLength))); // -fvisibility= and -fvisibility-ms-compat are of a piece. if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, @@ -5701,7 +5706,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager, options::OPT_fno_experimental_new_pass_manager); - ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); + ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, Inputs, CmdArgs, rewriteKind); RenderObjCOptions(TC, D, RawTriple, Args, Runtime, rewriteKind != RK_None, Input, CmdArgs); @@ -6218,10 +6223,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (SplitLTOUnit) CmdArgs.push_back("-fsplit-lto-unit"); - if (Arg *A = Args.getLastArg(options::OPT_fexperimental_isel, - options::OPT_fno_experimental_isel)) { + if (Arg *A = Args.getLastArg(options::OPT_fglobal_isel, + options::OPT_fno_global_isel)) { CmdArgs.push_back("-mllvm"); - if (A->getOption().matches(options::OPT_fexperimental_isel)) { + if (A->getOption().matches(options::OPT_fglobal_isel)) { CmdArgs.push_back("-global-isel=1"); // GISel is on by default on AArch64 -O0, so don't bother adding @@ -6240,9 +6245,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-global-isel-abort=2"); if (!IsArchSupported) - D.Diag(diag::warn_drv_experimental_isel_incomplete) << Triple.getArchName(); + D.Diag(diag::warn_drv_global_isel_incomplete) << Triple.getArchName(); else - D.Diag(diag::warn_drv_experimental_isel_incomplete_opt); + D.Diag(diag::warn_drv_global_isel_incomplete_opt); } } else { CmdArgs.push_back("-global-isel=0"); @@ -6408,6 +6413,7 @@ Clang::~Clang() {} /// /// Returns true if the runtime is non-fragile. ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, + const InputInfoList &inputs, ArgStringList &cmdArgs, RewriteKind rewriteKind) const { // Look for the controlling runtime option. @@ -6531,8 +6537,11 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); } - cmdArgs.push_back( - args.MakeArgString("-fobjc-runtime=" + runtime.getAsString())); + if (llvm::any_of(inputs, [](const InputInfo &input) { + return types::isObjC(input.getType()); + })) + cmdArgs.push_back( + args.MakeArgString("-fobjc-runtime=" + runtime.getAsString())); return runtime; } diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 1552515c1461a..64af2fdd5115c 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -77,6 +77,7 @@ class LLVM_LIBRARY_VISIBILITY Clang : public Tool { enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, + const InputInfoList &inputs, llvm::opt::ArgStringList &cmdArgs, RewriteKind rewrite) const; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index ebdb22fae3963..2ca50fb948bb9 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -50,6 +50,7 @@ #include "llvm/Support/Program.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLParser.h" @@ -346,14 +347,14 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, } } -unsigned tools::getLTOParallelism(const ArgList &Args, const Driver &D) { - unsigned Parallelism = 0; +llvm::StringRef tools::getLTOParallelism(const ArgList &Args, const Driver &D) { Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ); - if (LtoJobsArg && - StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism)) - D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args) - << LtoJobsArg->getValue(); - return Parallelism; + if (!LtoJobsArg) + return {}; + if (!llvm::get_threadpool_strategy(LtoJobsArg->getValue())) + D.Diag(diag::err_drv_invalid_int_value) + << LtoJobsArg->getAsString(Args) << LtoJobsArg->getValue(); + return LtoJobsArg->getValue(); } // CloudABI uses -ffunction-sections and -fdata-sections by default. @@ -418,7 +419,8 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, if (IsThinLTO) CmdArgs.push_back("-plugin-opt=thinlto"); - if (unsigned Parallelism = getLTOParallelism(Args, ToolChain.getDriver())) + StringRef Parallelism = getLTOParallelism(Args, ToolChain.getDriver()); + if (!Parallelism.empty()) CmdArgs.push_back( Args.MakeArgString("-plugin-opt=jobs=" + Twine(Parallelism))); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index 984f3ee98af1e..c94b2b828c9b8 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -88,7 +88,8 @@ llvm::opt::Arg *getLastProfileSampleUseArg(const llvm::opt::ArgList &Args); bool isObjCAutoRefCount(const llvm::opt::ArgList &Args); -unsigned getLTOParallelism(const llvm::opt::ArgList &Args, const Driver &D); +llvm::StringRef getLTOParallelism(const llvm::opt::ArgList &Args, + const Driver &D); bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index d1aec649cdc71..451d0d206d07d 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/Threading.h" #include "llvm/Support/VirtualFileSystem.h" #include // ::getenv @@ -605,10 +606,12 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, getMachOToolChain().addProfileRTLibs(Args, CmdArgs); - if (unsigned Parallelism = - getLTOParallelism(Args, getToolChain().getDriver())) { + StringRef Parallelism = getLTOParallelism(Args, getToolChain().getDriver()); + if (!Parallelism.empty()) { CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-threads=" + Twine(Parallelism))); + unsigned NumThreads = + llvm::get_threadpool_strategy(Parallelism)->compute_thread_count(); + CmdArgs.push_back(Args.MakeArgString("-threads=" + Twine(NumThreads))); } if (getToolChain().ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index 157dca7e0c8db..e4ace81dbac79 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "HIP.h" +#include "AMDGPU.h" #include "CommonArgs.h" #include "InputInfo.h" #include "clang/Basic/Cuda.h" @@ -16,6 +17,7 @@ #include "clang/Driver/Options.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TargetParser.h" using namespace clang::driver; using namespace clang::driver::toolchains; @@ -266,7 +268,7 @@ void AMDGCN::Linker::ConstructJob(Compilation &C, const JobAction &JA, HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, const ToolChain &HostTC, const ArgList &Args) - : ToolChain(D, Triple, Args), HostTC(HostTC) { + : AMDGPUToolChain(D, Triple, Args), HostTC(HostTC) { // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. getProgramPaths().push_back(getDriver().Dir); @@ -283,6 +285,7 @@ void HIPToolChain::addClangTargetOptions( (void) GpuArch; assert(DeviceOffloadingKind == Action::OFK_HIP && "Only HIP offloading kinds are supported for GPUs."); + auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); CC1Args.push_back("-target-cpu"); CC1Args.push_back(DriverArgs.MakeArgStringRef(GpuArch)); @@ -343,11 +346,14 @@ void HIPToolChain::addClangTargetOptions( std::string GFXVersion = GpuArch.drop_front(3).str(); std::string ISAVerBC = "oclc_isa_version_" + GFXVersion + ".amdgcn.bc"; - llvm::StringRef FlushDenormalControlBC; - if (DriverArgs.hasArg(options::OPT_fcuda_flush_denormals_to_zero)) - FlushDenormalControlBC = "oclc_daz_opt_on.amdgcn.bc"; - else - FlushDenormalControlBC = "oclc_daz_opt_off.amdgcn.bc"; + bool FTZDAZ = DriverArgs.hasFlag( + options::OPT_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, + getDefaultDenormsAreZeroForTarget(Kind)); + + std::string FlushDenormalControlBC = FTZDAZ ? + "oclc_daz_opt_on.amdgcn.bc" : + "oclc_daz_opt_off.amdgcn.bc"; llvm::StringRef WaveFrontSizeBC; if (stoi(GFXVersion) < 1000) @@ -357,7 +363,7 @@ void HIPToolChain::addClangTargetOptions( BCLibs.append({"hip.amdgcn.bc", "ocml.amdgcn.bc", "ockl.amdgcn.bc", "oclc_finite_only_off.amdgcn.bc", - std::string(FlushDenormalControlBC), + FlushDenormalControlBC, "oclc_correctly_rounded_sqrt_on.amdgcn.bc", "oclc_unsafe_math_off.amdgcn.bc", ISAVerBC, std::string(WaveFrontSizeBC)}); diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h index c4f944e458bf2..b6a3a27186353 100644 --- a/clang/lib/Driver/ToolChains/HIP.h +++ b/clang/lib/Driver/ToolChains/HIP.h @@ -11,6 +11,7 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Tool.h" +#include "AMDGPU.h" namespace clang { namespace driver { @@ -72,7 +73,7 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { namespace toolchains { -class LLVM_LIBRARY_VISIBILITY HIPToolChain : public ToolChain { +class LLVM_LIBRARY_VISIBILITY HIPToolChain final : public AMDGPUToolChain { public: HIPToolChain(const Driver &D, const llvm::Triple &Triple, const ToolChain &HostTC, const llvm::opt::ArgList &Args); diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index 9ecbb7241d454..ebeed3803e06d 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -434,3 +434,17 @@ SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { Res |= SanitizerKind::Vptr; return Res; } + +void toolchains::PS4CPU::addClangTargetOptions( + const ArgList &DriverArgs, + ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + // PS4 does not use init arrays. + if (DriverArgs.hasArg(options::OPT_fuse_init_array)) { + Arg *A = DriverArgs.getLastArg(options::OPT_fuse_init_array); + getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target) + << A->getAsString(DriverArgs) << getTriple().str(); + } + + CC1Args.push_back("-fno-use-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index c82b0c3a1b56a..8fedb6eda0eff 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -88,6 +88,11 @@ class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { // capable of unit splitting. bool canSplitThinLTOUnit() const override { return false; } + void addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const override; + llvm::DenormalMode getDefaultDenormalModeForType( const llvm::opt::ArgList &DriverArgs, Action::OffloadKind DeviceOffloadKind, diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index d2397dbfeb87b..ba42ba0ca0500 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -346,6 +346,11 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { Current.startsSequence(TT_SelectorName, tok::colon, tok::caret)) { return true; } + // Avoid producing inconsistent states by requiring breaks where they are not + // permitted for C# generic type constraints. + if (State.Stack.back().IsCSharpGenericTypeConstraint && + Previous.isNot(TT_CSharpGenericTypeConstraintComma)) + return false; if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) || (Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) && Style.isCpp() && diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 10a5f0e96f96f..48ec7602c21c2 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -910,9 +910,64 @@ struct AdditionalKeywords { /// Returns \c true if \p Tok is a true JavaScript identifier, returns /// \c false if it is a keyword or a pseudo keyword. bool IsJavaScriptIdentifier(const FormatToken &Tok) const { - return Tok.is(tok::identifier) && - JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) == - JsExtraKeywords.end(); + // Based on the list of JavaScript & TypeScript keywords here: + // https://github.com/microsoft/TypeScript/blob/master/src/compiler/scanner.ts#L74 + switch (Tok.Tok.getKind()) { + case tok::kw_break: + case tok::kw_case: + case tok::kw_catch: + case tok::kw_class: + case tok::kw_continue: + case tok::kw_const: + case tok::kw_default: + case tok::kw_delete: + case tok::kw_do: + case tok::kw_else: + case tok::kw_enum: + case tok::kw_export: + case tok::kw_false: + case tok::kw_for: + case tok::kw_if: + case tok::kw_import: + case tok::kw_module: + case tok::kw_new: + case tok::kw_private: + case tok::kw_protected: + case tok::kw_public: + case tok::kw_return: + case tok::kw_static: + case tok::kw_switch: + case tok::kw_this: + case tok::kw_throw: + case tok::kw_true: + case tok::kw_try: + case tok::kw_typeof: + case tok::kw_void: + case tok::kw_while: + // These are JS keywords that are lexed by LLVM/clang as keywords. + return false; + case tok::identifier: + // For identifiers, make sure they are true identifiers, excluding the + // JavaScript pseudo-keywords (not lexed by LLVM/clang as keywords). + return JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) == + JsExtraKeywords.end(); + default: + // Other keywords are handled in the switch below, to avoid problems due + // to duplicate case labels when using the #include trick. + break; + } + + switch (Tok.Tok.getKind()) { + // Handle C++ keywords not included above: these are all JS identifiers. +#define KEYWORD(X, Y) case tok::kw_##X: +#include "clang/Basic/TokenKinds.def" + // #undef KEYWORD is not needed -- it's #undef-ed at the end of + // TokenKinds.def + return true; + default: + // All other tokens (punctuation etc) are not JS identifiers. + return false; + } } /// Returns \c true if \p Tok is a C# keyword, returns diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index f2666a8bd1717..029741c3dce70 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1047,7 +1047,7 @@ class AnnotatingParser { Keywords.kw___has_include_next)) { parseHasInclude(); } - if (Tok->is(Keywords.kw_where) && Tok->Next && + if (Style.isCSharp() && Tok->is(Keywords.kw_where) && Tok->Next && Tok->Next->isNot(tok::l_paren)) { Tok->Type = TT_CSharpGenericTypeConstraint; parseCSharpGenericTypeConstraint(); @@ -1060,15 +1060,20 @@ class AnnotatingParser { } void parseCSharpGenericTypeConstraint() { + int OpenAngleBracketsCount = 0; while (CurrentToken) { if (CurrentToken->is(tok::less)) { // parseAngle is too greedy and will consume the whole line. CurrentToken->Type = TT_TemplateOpener; + ++OpenAngleBracketsCount; next(); } else if (CurrentToken->is(tok::greater)) { CurrentToken->Type = TT_TemplateCloser; + --OpenAngleBracketsCount; next(); - } else if (CurrentToken->is(tok::comma)) { + } else if (CurrentToken->is(tok::comma) && OpenAngleBracketsCount == 0) { + // We allow line breaks after GenericTypeConstraintComma's + // so do not flag commas in Generics as GenericTypeConstraintComma's. CurrentToken->Type = TT_CSharpGenericTypeConstraintComma; next(); } else if (CurrentToken->is(Keywords.kw_where)) { @@ -1517,9 +1522,9 @@ class AnnotatingParser { if (Style.Language == FormatStyle::LK_JavaScript) { if (Current.is(tok::exclaim)) { if (Current.Previous && - (Current.Previous->isOneOf(tok::identifier, tok::kw_namespace, - tok::r_paren, tok::r_square, - tok::r_brace) || + (Keywords.IsJavaScriptIdentifier(*Current.Previous) || + Current.Previous->isOneOf(tok::kw_namespace, tok::r_paren, + tok::r_square, tok::r_brace) || Current.Previous->Tok.isLiteral())) { Current.Type = TT_JsNonNullAssertion; return; @@ -2799,20 +2804,38 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, tok::l_square)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; - if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) && - (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) && - // Space between the type and the * in: - // operator void*() - // operator char*() - // operator /*comment*/ const char*() - // operator volatile /*comment*/ char*() - // operator Foo*() - // dependent on PointerAlignment style. - Left.Previous && - (Left.Previous->endsSequence(tok::kw_operator) || - Left.Previous->endsSequence(tok::kw_const, tok::kw_operator) || - Left.Previous->endsSequence(tok::kw_volatile, tok::kw_operator))) - return (Style.PointerAlignment != FormatStyle::PAS_Left); + if (Right.isOneOf(tok::star, tok::amp, tok::ampamp)) { + const FormatToken *Previous = &Left; + while (Previous && !Previous->is(tok::kw_operator)) { + if (Previous->is(tok::identifier) || Previous->isSimpleTypeSpecifier()) { + Previous = Previous->getPreviousNonComment(); + continue; + } + if (Previous->is(TT_TemplateCloser) && Previous->MatchingParen) { + Previous = Previous->MatchingParen->getPreviousNonComment(); + continue; + } + if (Previous->is(tok::coloncolon)) { + Previous = Previous->getPreviousNonComment(); + continue; + } + break; + } + // Space between the type and the * in: + // operator void*() + // operator char*() + // operator /*comment*/ const char*() + // operator volatile /*comment*/ char*() + // operator Foo*() + // operator C*() + // operator std::Foo*() + // operator C::D*() + // dependent on PointerAlignment style. + if (Previous && (Previous->endsSequence(tok::kw_operator) || + Previous->endsSequence(tok::kw_const, tok::kw_operator) || + Previous->endsSequence(tok::kw_volatile, tok::kw_operator))) + return (Style.PointerAlignment != FormatStyle::PAS_Left); + } const auto SpaceRequiredForArrayInitializerLSquare = [](const FormatToken &LSquareTok, const FormatStyle &Style) { return Style.SpacesInContainerLiterals || @@ -3047,10 +3070,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) return false; // In tagged template literals ("html`bar baz`"), there is no space between - // the tag identifier and the template string. getIdentifierInfo makes sure - // that the identifier is not a pseudo keyword like `yield`, either. - if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) && - Right.is(TT_TemplateString)) + // the tag identifier and the template string. + if (Keywords.IsJavaScriptIdentifier(Left) && Right.is(TT_TemplateString)) return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index d8202bd614580..18899314512e3 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -2340,6 +2340,12 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr) { } if (FormatTok->Tok.is(tok::semi)) return; + if (Style.isCSharp() && FormatTok->is(Keywords.kw_where)) { + addUnwrappedLine(); + nextToken(); + parseCSharpGenericTypeConstraint(); + break; + } nextToken(); } } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 646ce7852da47..75cd7ea34e63f 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -827,6 +827,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.RerollLoops = Args.hasArg(OPT_freroll_loops); Opts.DisableIntegratedAS = Args.hasArg(OPT_fno_integrated_as); + Opts.CallGraphProfile = !Opts.DisableIntegratedAS; Opts.Autolink = !Args.hasArg(OPT_fno_autolink); Opts.SampleProfileFile = std::string(Args.getLastArgValue(OPT_fprofile_sample_use_EQ)); @@ -858,7 +859,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.CoverageMapping = Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false); Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); - Opts.AsmVerbose = Args.hasArg(OPT_masm_verbose); + Opts.AsmVerbose = !Args.hasArg(OPT_fno_verbose_asm); Opts.PreserveAsmComments = !Args.hasArg(OPT_fno_preserve_as_comments); Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); @@ -1390,38 +1391,6 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.Addrsig = Args.hasArg(OPT_faddrsig); - if (Arg *A = Args.getLastArg(OPT_msign_return_address_EQ)) { - StringRef SignScope = A->getValue(); - - if (SignScope.equals_lower("none")) - Opts.setSignReturnAddress(CodeGenOptions::SignReturnAddressScope::None); - else if (SignScope.equals_lower("all")) - Opts.setSignReturnAddress(CodeGenOptions::SignReturnAddressScope::All); - else if (SignScope.equals_lower("non-leaf")) - Opts.setSignReturnAddress( - CodeGenOptions::SignReturnAddressScope::NonLeaf); - else - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << SignScope; - - if (Arg *A = Args.getLastArg(OPT_msign_return_address_key_EQ)) { - StringRef SignKey = A->getValue(); - if (!SignScope.empty() && !SignKey.empty()) { - if (SignKey.equals_lower("a_key")) - Opts.setSignReturnAddressKey( - CodeGenOptions::SignReturnAddressKeyValue::AKey); - else if (SignKey.equals_lower("b_key")) - Opts.setSignReturnAddressKey( - CodeGenOptions::SignReturnAddressKeyValue::BKey); - else - Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << SignKey; - } - } - } - - Opts.BranchTargetEnforcement = Args.hasArg(OPT_mbranch_target_enforce); - Opts.KeepStaticConsts = Args.hasArg(OPT_fkeep_static_consts); Opts.SpeculativeLoadHardening = Args.hasArg(OPT_mspeculative_load_hardening); @@ -1552,7 +1521,7 @@ static bool checkVerifyPrefixes(const std::vector &VerifyPrefixes, bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, - bool DefaultDiagColor, bool DefaultShowOpt) { + bool DefaultDiagColor) { bool Success = true; Opts.DiagnosticLogFile = @@ -1570,9 +1539,7 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); Opts.AbsolutePath = Args.hasArg(OPT_fdiagnostics_absolute_paths); - Opts.ShowOptionNames = - Args.hasFlag(OPT_fdiagnostics_show_option, - OPT_fno_diagnostics_show_option, DefaultShowOpt); + Opts.ShowOptionNames = !Args.hasArg(OPT_fno_diagnostics_show_option); llvm::sys::Process::UseANSIEscapeCodes(Args.hasArg(OPT_fansi_escape_codes)); @@ -1680,7 +1647,8 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Diags->Report(diag::warn_ignoring_ftabstop_value) << Opts.TabStop << DiagnosticOptions::DefaultTabStop; } - Opts.MessageLength = getLastArgIntValue(Args, OPT_fmessage_length, 0, Diags); + Opts.MessageLength = + getLastArgIntValue(Args, OPT_fmessage_length_EQ, 0, Diags); addDiagnosticArgs(Args, OPT_W_Group, OPT_W_value_Group, Opts.Warnings); addDiagnosticArgs(Args, OPT_R_Group, OPT_R_value_Group, Opts.Remarks); @@ -1786,25 +1754,26 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, StringRef ArgStr = Args.hasArg(OPT_interface_stub_version_EQ) ? Args.getLastArgValue(OPT_interface_stub_version_EQ) - : "experimental-ifs-v1"; + : "experimental-ifs-v2"; if (ArgStr == "experimental-yaml-elf-v1" || + ArgStr == "experimental-ifs-v1" || ArgStr == "experimental-tapi-elf-v1") { std::string ErrorMessage = "Invalid interface stub format: " + ArgStr.str() + " is deprecated."; Diags.Report(diag::err_drv_invalid_value) << "Must specify a valid interface stub format type, ie: " - "-interface-stub-version=experimental-ifs-v1" + "-interface-stub-version=experimental-ifs-v2" << ErrorMessage; - } else if (ArgStr != "experimental-ifs-v1") { + } else if (!ArgStr.startswith("experimental-ifs-")) { std::string ErrorMessage = "Invalid interface stub format: " + ArgStr.str() + "."; Diags.Report(diag::err_drv_invalid_value) << "Must specify a valid interface stub format type, ie: " - "-interface-stub-version=experimental-ifs-v1" + "-interface-stub-version=experimental-ifs-v2" << ErrorMessage; } else { - Opts.ProgramAction = frontend::GenerateInterfaceIfsExpV1; + Opts.ProgramAction = frontend::GenerateInterfaceStubs; } break; } @@ -2926,7 +2895,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_fconcepts_ts)) Diags.Report(diag::warn_fe_concepts_ts_flag); Opts.RecoveryAST = - Args.hasFlag(OPT_frecovery_ast, OPT_fno_recovery_ast, Opts.CPlusPlus); + Args.hasFlag(OPT_frecovery_ast, OPT_fno_recovery_ast, false); Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions); Opts.AccessControl = !Args.hasArg(OPT_fno_access_control); Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors); @@ -3364,6 +3333,40 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.BuildingPCHWithObjectFile = Args.hasArg(OPT_building_pch_with_obj); Opts.MaxTokens = getLastArgIntValue(Args, OPT_fmax_tokens_EQ, 0, Diags); + + if (Arg *A = Args.getLastArg(OPT_msign_return_address_EQ)) { + StringRef SignScope = A->getValue(); + + if (SignScope.equals_lower("none")) + Opts.setSignReturnAddressScope( + LangOptions::SignReturnAddressScopeKind::None); + else if (SignScope.equals_lower("all")) + Opts.setSignReturnAddressScope( + LangOptions::SignReturnAddressScopeKind::All); + else if (SignScope.equals_lower("non-leaf")) + Opts.setSignReturnAddressScope( + LangOptions::SignReturnAddressScopeKind::NonLeaf); + else + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << SignScope; + + if (Arg *A = Args.getLastArg(OPT_msign_return_address_key_EQ)) { + StringRef SignKey = A->getValue(); + if (!SignScope.empty() && !SignKey.empty()) { + if (SignKey.equals_lower("a_key")) + Opts.setSignReturnAddressKey( + LangOptions::SignReturnAddressKeyKind::AKey); + else if (SignKey.equals_lower("b_key")) + Opts.setSignReturnAddressKey( + LangOptions::SignReturnAddressKeyKind::BKey); + else + Diags.Report(diag::err_drv_invalid_value) + << A->getAsString(Args) << SignKey; + } + } + } + + Opts.BranchTargetEnforcement = Args.hasArg(OPT_mbranch_target_enforce); } static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { @@ -3384,7 +3387,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::GenerateModuleInterface: case frontend::GenerateHeaderModule: case frontend::GeneratePCH: - case frontend::GenerateInterfaceIfsExpV1: + case frontend::GenerateInterfaceStubs: case frontend::ParseSyntaxOnly: case frontend::ModuleFileInfo: case frontend::VerifyPCH: @@ -3612,9 +3615,8 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, Diags.Report(diag::err_fe_dependency_file_requires_MT); Success = false; } - Success &= - ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags, - false /*DefaultDiagColor*/, false /*DefaultShowOpt*/); + Success &= ParseDiagnosticArgs(Res.getDiagnosticOpts(), Args, &Diags, + /*DefaultDiagColor=*/false); ParseCommentArgs(LangOpts.CommentOpts, Args); ParseFileSystemArgs(Res.getFileSystemOpts(), Args); // FIXME: We shouldn't have to pass the DashX option around here diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 1dc85d967ca01..0155238dd0a82 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -1081,6 +1081,9 @@ void WrapperFrontendAction::ExecuteAction() { void WrapperFrontendAction::EndSourceFileAction() { WrappedAction->EndSourceFileAction(); } +bool WrapperFrontendAction::shouldEraseOutputFiles() { + return WrappedAction->shouldEraseOutputFiles(); +} bool WrapperFrontendAction::usesPreprocessorOnly() const { return WrappedAction->usesPreprocessorOnly(); diff --git a/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp b/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp index 2b7f0f8f9b663..b7c1e693413b7 100644 --- a/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp +++ b/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp @@ -290,7 +290,7 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer { const ASTContext &context, StringRef Format, raw_ostream &OS) -> void { OS << "--- !" << Format << "\n"; - OS << "IfsVersion: 1.0\n"; + OS << "IfsVersion: 2.0\n"; OS << "Triple: " << T.str() << "\n"; OS << "ObjectFileFormat: " << "ELF" @@ -299,11 +299,11 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer { for (const auto &E : Symbols) { const MangledSymbol &Symbol = E.second; for (auto Name : Symbol.Names) { - OS << " \"" + OS << " - { Name: \"" << (Symbol.ParentName.empty() || Instance.getLangOpts().CPlusPlus ? "" : (Symbol.ParentName + ".")) - << Name << "\" : { Type: "; + << Name << "\", Type: "; switch (Symbol.Type) { default: llvm_unreachable( @@ -330,15 +330,15 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer { OS.flush(); }; - assert(Format == "experimental-ifs-v1" && "Unexpected IFS Format."); + assert(Format == "experimental-ifs-v2" && "Unexpected IFS Format."); writeIfsV1(Instance.getTarget().getTriple(), Symbols, context, Format, *OS); } }; } // namespace std::unique_ptr -GenerateInterfaceIfsExpV1Action::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { +GenerateInterfaceStubsAction::CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) { return std::make_unique( - CI, InFile, "experimental-ifs-v1"); + CI, InFile, "experimental-ifs-v2"); } diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 70735ab2d7b2e..7c59ae42d2a28 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -23,6 +23,7 @@ #include "clang/Frontend/Utils.h" #include "clang/FrontendTool/Utils.h" #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" @@ -64,8 +65,8 @@ CreateFrontendBaseAction(CompilerInstance &CI) { case GenerateHeaderModule: return std::make_unique(); case GeneratePCH: return std::make_unique(); - case GenerateInterfaceIfsExpV1: - return std::make_unique(); + case GenerateInterfaceStubs: + return std::make_unique(); case InitOnly: return std::make_unique(); case ParseSyntaxOnly: return std::make_unique(); case ModuleFileInfo: return std::make_unique(); @@ -243,35 +244,24 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { // These should happen AFTER plugins have been loaded! AnalyzerOptions &AnOpts = *Clang->getAnalyzerOpts(); + // Honor -analyzer-checker-help and -analyzer-checker-help-hidden. if (AnOpts.ShowCheckerHelp || AnOpts.ShowCheckerHelpAlpha || AnOpts.ShowCheckerHelpDeveloper) { - ento::printCheckerHelp(llvm::outs(), - Clang->getFrontendOpts().Plugins, - AnOpts, - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printCheckerHelp(llvm::outs(), *Clang); return true; } // Honor -analyzer-checker-option-help. if (AnOpts.ShowCheckerOptionList || AnOpts.ShowCheckerOptionAlphaList || AnOpts.ShowCheckerOptionDeveloperList) { - ento::printCheckerConfigList(llvm::outs(), - Clang->getFrontendOpts().Plugins, - *Clang->getAnalyzerOpts(), - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printCheckerConfigList(llvm::outs(), *Clang); return true; } // Honor -analyzer-list-enabled-checkers. if (AnOpts.ShowEnabledCheckerList) { - ento::printEnabledCheckerList(llvm::outs(), - Clang->getFrontendOpts().Plugins, - AnOpts, - Clang->getDiagnostics(), - Clang->getLangOpts()); + ento::printEnabledCheckerList(llvm::outs(), *Clang); return true; } diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 28d43cb7ed35a..6851957600e05 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -37,6 +37,7 @@ set(files bmi2intrin.h bmiintrin.h __clang_cuda_builtin_vars.h + __clang_cuda_math.h __clang_cuda_cmath.h __clang_cuda_complex_builtins.h __clang_cuda_device_functions.h @@ -87,6 +88,7 @@ set(files ptwriteintrin.h rdseedintrin.h rtmintrin.h + serializeintrin.h sgxintrin.h s390intrin.h shaintrin.h @@ -109,6 +111,7 @@ set(files vecintrin.h vpclmulqdqintrin.h waitpkgintrin.h + wasm_simd128.h wbnoinvdintrin.h wmmintrin.h __wmmintrin_aes.h diff --git a/clang/lib/Headers/__clang_cuda_device_functions.h b/clang/lib/Headers/__clang_cuda_device_functions.h index 50ad674f94830..d15f6b61d6ef2 100644 --- a/clang/lib/Headers/__clang_cuda_device_functions.h +++ b/clang/lib/Headers/__clang_cuda_device_functions.h @@ -26,26 +26,6 @@ #define __DEVICE__ static __device__ __forceinline__ #endif -// libdevice provides fast low precision and slow full-recision implementations -// for some functions. Which one gets selected depends on -// __CLANG_CUDA_APPROX_TRANSCENDENTALS__ which gets defined by clang if -// -ffast-math or -fcuda-approx-transcendentals are in effect. -#pragma push_macro("__FAST_OR_SLOW") -#if defined(__CLANG_CUDA_APPROX_TRANSCENDENTALS__) -#define __FAST_OR_SLOW(fast, slow) fast -#else -#define __FAST_OR_SLOW(fast, slow) slow -#endif - -// For C++ 17 we need to include noexcept attribute to be compatible -// with the header-defined version. This may be removed once -// variant is supported. -#if defined(_OPENMP) && defined(__cplusplus) && __cplusplus >= 201703L -#define __NOEXCEPT noexcept -#else -#define __NOEXCEPT -#endif - __DEVICE__ int __all(int __a) { return __nvvm_vote_all(__a); } __DEVICE__ int __any(int __a) { return __nvvm_vote_any(__a); } __DEVICE__ unsigned int __ballot(int __a) { return __nvvm_vote_ballot(__a); } @@ -359,10 +339,10 @@ __DEVICE__ int __iAtomicAdd(int *__p, int __v) { return __nvvm_atom_add_gen_i(__p, __v); } __DEVICE__ int __iAtomicAdd_block(int *__p, int __v) { - __nvvm_atom_cta_add_gen_i(__p, __v); + return __nvvm_atom_cta_add_gen_i(__p, __v); } __DEVICE__ int __iAtomicAdd_system(int *__p, int __v) { - __nvvm_atom_sys_add_gen_i(__p, __v); + return __nvvm_atom_sys_add_gen_i(__p, __v); } __DEVICE__ int __iAtomicAnd(int *__p, int __v) { return __nvvm_atom_and_gen_i(__p, __v); @@ -1483,149 +1463,14 @@ __DEVICE__ unsigned int __vsubus4(unsigned int __a, unsigned int __b) { return r; } #endif // CUDA_VERSION >= 9020 -__DEVICE__ int abs(int __a) __NOEXCEPT { return __nv_abs(__a); } -__DEVICE__ double fabs(double __a) __NOEXCEPT { return __nv_fabs(__a); } -__DEVICE__ double acos(double __a) { return __nv_acos(__a); } -__DEVICE__ float acosf(float __a) { return __nv_acosf(__a); } -__DEVICE__ double acosh(double __a) { return __nv_acosh(__a); } -__DEVICE__ float acoshf(float __a) { return __nv_acoshf(__a); } -__DEVICE__ double asin(double __a) { return __nv_asin(__a); } -__DEVICE__ float asinf(float __a) { return __nv_asinf(__a); } -__DEVICE__ double asinh(double __a) { return __nv_asinh(__a); } -__DEVICE__ float asinhf(float __a) { return __nv_asinhf(__a); } -__DEVICE__ double atan(double __a) { return __nv_atan(__a); } -__DEVICE__ double atan2(double __a, double __b) { return __nv_atan2(__a, __b); } -__DEVICE__ float atan2f(float __a, float __b) { return __nv_atan2f(__a, __b); } -__DEVICE__ float atanf(float __a) { return __nv_atanf(__a); } -__DEVICE__ double atanh(double __a) { return __nv_atanh(__a); } -__DEVICE__ float atanhf(float __a) { return __nv_atanhf(__a); } -__DEVICE__ double cbrt(double __a) { return __nv_cbrt(__a); } -__DEVICE__ float cbrtf(float __a) { return __nv_cbrtf(__a); } -__DEVICE__ double ceil(double __a) { return __nv_ceil(__a); } -__DEVICE__ float ceilf(float __a) { return __nv_ceilf(__a); } + +// For OpenMP we require the user to include as we need to know what +// clock_t is on the system. #ifndef _OPENMP -__DEVICE__ int clock() { return __nvvm_read_ptx_sreg_clock(); } -__DEVICE__ long long clock64() { return __nvvm_read_ptx_sreg_clock64(); } -#endif -__DEVICE__ double copysign(double __a, double __b) { - return __nv_copysign(__a, __b); -} -__DEVICE__ float copysignf(float __a, float __b) { - return __nv_copysignf(__a, __b); -} -__DEVICE__ double cos(double __a) { return __nv_cos(__a); } -__DEVICE__ float cosf(float __a) { - return __FAST_OR_SLOW(__nv_fast_cosf, __nv_cosf)(__a); -} -__DEVICE__ double cosh(double __a) { return __nv_cosh(__a); } -__DEVICE__ float coshf(float __a) { return __nv_coshf(__a); } -__DEVICE__ double cospi(double __a) { return __nv_cospi(__a); } -__DEVICE__ float cospif(float __a) { return __nv_cospif(__a); } -__DEVICE__ double cyl_bessel_i0(double __a) { return __nv_cyl_bessel_i0(__a); } -__DEVICE__ float cyl_bessel_i0f(float __a) { return __nv_cyl_bessel_i0f(__a); } -__DEVICE__ double cyl_bessel_i1(double __a) { return __nv_cyl_bessel_i1(__a); } -__DEVICE__ float cyl_bessel_i1f(float __a) { return __nv_cyl_bessel_i1f(__a); } -__DEVICE__ double erf(double __a) { return __nv_erf(__a); } -__DEVICE__ double erfc(double __a) { return __nv_erfc(__a); } -__DEVICE__ float erfcf(float __a) { return __nv_erfcf(__a); } -__DEVICE__ double erfcinv(double __a) { return __nv_erfcinv(__a); } -__DEVICE__ float erfcinvf(float __a) { return __nv_erfcinvf(__a); } -__DEVICE__ double erfcx(double __a) { return __nv_erfcx(__a); } -__DEVICE__ float erfcxf(float __a) { return __nv_erfcxf(__a); } -__DEVICE__ float erff(float __a) { return __nv_erff(__a); } -__DEVICE__ double erfinv(double __a) { return __nv_erfinv(__a); } -__DEVICE__ float erfinvf(float __a) { return __nv_erfinvf(__a); } -__DEVICE__ double exp(double __a) { return __nv_exp(__a); } -__DEVICE__ double exp10(double __a) { return __nv_exp10(__a); } -__DEVICE__ float exp10f(float __a) { return __nv_exp10f(__a); } -__DEVICE__ double exp2(double __a) { return __nv_exp2(__a); } -__DEVICE__ float exp2f(float __a) { return __nv_exp2f(__a); } -__DEVICE__ float expf(float __a) { return __nv_expf(__a); } -__DEVICE__ double expm1(double __a) { return __nv_expm1(__a); } -__DEVICE__ float expm1f(float __a) { return __nv_expm1f(__a); } -__DEVICE__ float fabsf(float __a) { return __nv_fabsf(__a); } -__DEVICE__ double fdim(double __a, double __b) { return __nv_fdim(__a, __b); } -__DEVICE__ float fdimf(float __a, float __b) { return __nv_fdimf(__a, __b); } -__DEVICE__ double fdivide(double __a, double __b) { return __a / __b; } -__DEVICE__ float fdividef(float __a, float __b) { -#if __FAST_MATH__ && !__CUDA_PREC_DIV - return __nv_fast_fdividef(__a, __b); -#else - return __a / __b; +__DEVICE__ /* clock_t= */ int clock() { return __nvvm_read_ptx_sreg_clock(); } #endif -} -__DEVICE__ double floor(double __f) { return __nv_floor(__f); } -__DEVICE__ float floorf(float __f) { return __nv_floorf(__f); } -__DEVICE__ double fma(double __a, double __b, double __c) { - return __nv_fma(__a, __b, __c); -} -__DEVICE__ float fmaf(float __a, float __b, float __c) { - return __nv_fmaf(__a, __b, __c); -} -__DEVICE__ double fmax(double __a, double __b) { return __nv_fmax(__a, __b); } -__DEVICE__ float fmaxf(float __a, float __b) { return __nv_fmaxf(__a, __b); } -__DEVICE__ double fmin(double __a, double __b) { return __nv_fmin(__a, __b); } -__DEVICE__ float fminf(float __a, float __b) { return __nv_fminf(__a, __b); } -__DEVICE__ double fmod(double __a, double __b) { return __nv_fmod(__a, __b); } -__DEVICE__ float fmodf(float __a, float __b) { return __nv_fmodf(__a, __b); } -__DEVICE__ double frexp(double __a, int *__b) { return __nv_frexp(__a, __b); } -__DEVICE__ float frexpf(float __a, int *__b) { return __nv_frexpf(__a, __b); } -__DEVICE__ double hypot(double __a, double __b) { return __nv_hypot(__a, __b); } -__DEVICE__ float hypotf(float __a, float __b) { return __nv_hypotf(__a, __b); } -__DEVICE__ int ilogb(double __a) { return __nv_ilogb(__a); } -__DEVICE__ int ilogbf(float __a) { return __nv_ilogbf(__a); } -__DEVICE__ double j0(double __a) { return __nv_j0(__a); } -__DEVICE__ float j0f(float __a) { return __nv_j0f(__a); } -__DEVICE__ double j1(double __a) { return __nv_j1(__a); } -__DEVICE__ float j1f(float __a) { return __nv_j1f(__a); } -__DEVICE__ double jn(int __n, double __a) { return __nv_jn(__n, __a); } -__DEVICE__ float jnf(int __n, float __a) { return __nv_jnf(__n, __a); } -#if defined(__LP64__) || defined(_WIN64) -__DEVICE__ long labs(long __a) __NOEXCEPT { return __nv_llabs(__a); }; -#else -__DEVICE__ long labs(long __a) __NOEXCEPT { return __nv_abs(__a); }; -#endif -__DEVICE__ double ldexp(double __a, int __b) { return __nv_ldexp(__a, __b); } -__DEVICE__ float ldexpf(float __a, int __b) { return __nv_ldexpf(__a, __b); } -__DEVICE__ double lgamma(double __a) { return __nv_lgamma(__a); } -__DEVICE__ float lgammaf(float __a) { return __nv_lgammaf(__a); } -__DEVICE__ long long llabs(long long __a) __NOEXCEPT { return __nv_llabs(__a); } -__DEVICE__ long long llmax(long long __a, long long __b) { - return __nv_llmax(__a, __b); -} -__DEVICE__ long long llmin(long long __a, long long __b) { - return __nv_llmin(__a, __b); -} -__DEVICE__ long long llrint(double __a) { return __nv_llrint(__a); } -__DEVICE__ long long llrintf(float __a) { return __nv_llrintf(__a); } -__DEVICE__ long long llround(double __a) { return __nv_llround(__a); } -__DEVICE__ long long llroundf(float __a) { return __nv_llroundf(__a); } -__DEVICE__ double log(double __a) { return __nv_log(__a); } -__DEVICE__ double log10(double __a) { return __nv_log10(__a); } -__DEVICE__ float log10f(float __a) { return __nv_log10f(__a); } -__DEVICE__ double log1p(double __a) { return __nv_log1p(__a); } -__DEVICE__ float log1pf(float __a) { return __nv_log1pf(__a); } -__DEVICE__ double log2(double __a) { return __nv_log2(__a); } -__DEVICE__ float log2f(float __a) { - return __FAST_OR_SLOW(__nv_fast_log2f, __nv_log2f)(__a); -} -__DEVICE__ double logb(double __a) { return __nv_logb(__a); } -__DEVICE__ float logbf(float __a) { return __nv_logbf(__a); } -__DEVICE__ float logf(float __a) { - return __FAST_OR_SLOW(__nv_fast_logf, __nv_logf)(__a); -} -#if defined(__LP64__) || defined(_WIN64) -__DEVICE__ long lrint(double __a) { return llrint(__a); } -__DEVICE__ long lrintf(float __a) { return __float2ll_rn(__a); } -__DEVICE__ long lround(double __a) { return llround(__a); } -__DEVICE__ long lroundf(float __a) { return llroundf(__a); } -#else -__DEVICE__ long lrint(double __a) { return (long)rint(__a); } -__DEVICE__ long lrintf(float __a) { return __float2int_rn(__a); } -__DEVICE__ long lround(double __a) { return round(__a); } -__DEVICE__ long lroundf(float __a) { return roundf(__a); } -#endif -__DEVICE__ int max(int __a, int __b) { return __nv_max(__a, __b); } +__DEVICE__ long long clock64() { return __nvvm_read_ptx_sreg_clock64(); } + // These functions shouldn't be declared when including this header // for math function resolution purposes. #ifndef _OPENMP @@ -1636,158 +1481,6 @@ __DEVICE__ void *memset(void *__a, int __b, size_t __c) { return __builtin_memset(__a, __b, __c); } #endif -__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 nextafter(double __a, double __b) { - return __nv_nextafter(__a, __b); -} -__DEVICE__ float nextafterf(float __a, float __b) { - return __nv_nextafterf(__a, __b); -} -__DEVICE__ double norm(int __dim, const double *__t) { - return __nv_norm(__dim, __t); -} -__DEVICE__ double norm3d(double __a, double __b, double __c) { - return __nv_norm3d(__a, __b, __c); -} -__DEVICE__ float norm3df(float __a, float __b, float __c) { - return __nv_norm3df(__a, __b, __c); -} -__DEVICE__ double norm4d(double __a, double __b, double __c, double __d) { - return __nv_norm4d(__a, __b, __c, __d); -} -__DEVICE__ float norm4df(float __a, float __b, float __c, float __d) { - return __nv_norm4df(__a, __b, __c, __d); -} -__DEVICE__ double normcdf(double __a) { return __nv_normcdf(__a); } -__DEVICE__ float normcdff(float __a) { return __nv_normcdff(__a); } -__DEVICE__ double normcdfinv(double __a) { return __nv_normcdfinv(__a); } -__DEVICE__ float normcdfinvf(float __a) { return __nv_normcdfinvf(__a); } -__DEVICE__ float normf(int __dim, const float *__t) { - return __nv_normf(__dim, __t); -} -__DEVICE__ double pow(double __a, double __b) { return __nv_pow(__a, __b); } -__DEVICE__ float powf(float __a, float __b) { return __nv_powf(__a, __b); } -__DEVICE__ double powi(double __a, int __b) { return __nv_powi(__a, __b); } -__DEVICE__ float powif(float __a, int __b) { return __nv_powif(__a, __b); } -__DEVICE__ double rcbrt(double __a) { return __nv_rcbrt(__a); } -__DEVICE__ float rcbrtf(float __a) { return __nv_rcbrtf(__a); } -__DEVICE__ double remainder(double __a, double __b) { - return __nv_remainder(__a, __b); -} -__DEVICE__ float remainderf(float __a, float __b) { - return __nv_remainderf(__a, __b); -} -__DEVICE__ double remquo(double __a, double __b, int *__c) { - return __nv_remquo(__a, __b, __c); -} -__DEVICE__ float remquof(float __a, float __b, int *__c) { - return __nv_remquof(__a, __b, __c); -} -__DEVICE__ double rhypot(double __a, double __b) { - return __nv_rhypot(__a, __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); } -__DEVICE__ double rnorm(int __a, const double *__b) { - return __nv_rnorm(__a, __b); -} -__DEVICE__ double rnorm3d(double __a, double __b, double __c) { - return __nv_rnorm3d(__a, __b, __c); -} -__DEVICE__ float rnorm3df(float __a, float __b, float __c) { - return __nv_rnorm3df(__a, __b, __c); -} -__DEVICE__ double rnorm4d(double __a, double __b, double __c, double __d) { - return __nv_rnorm4d(__a, __b, __c, __d); -} -__DEVICE__ float rnorm4df(float __a, float __b, float __c, float __d) { - return __nv_rnorm4df(__a, __b, __c, __d); -} -__DEVICE__ float rnormf(int __dim, const float *__t) { - return __nv_rnormf(__dim, __t); -} -__DEVICE__ double round(double __a) { return __nv_round(__a); } -__DEVICE__ float roundf(float __a) { return __nv_roundf(__a); } -__DEVICE__ double rsqrt(double __a) { return __nv_rsqrt(__a); } -__DEVICE__ float rsqrtf(float __a) { return __nv_rsqrtf(__a); } -__DEVICE__ double scalbn(double __a, int __b) { return __nv_scalbn(__a, __b); } -__DEVICE__ float scalbnf(float __a, int __b) { return __nv_scalbnf(__a, __b); } -// TODO: remove once variant is supported -#ifndef _OPENMP -__DEVICE__ double scalbln(double __a, long __b) { - if (__b > INT_MAX) - return __a > 0 ? HUGE_VAL : -HUGE_VAL; - if (__b < INT_MIN) - return __a > 0 ? 0.0 : -0.0; - return scalbn(__a, (int)__b); -} -__DEVICE__ float scalblnf(float __a, long __b) { - if (__b > INT_MAX) - return __a > 0 ? HUGE_VALF : -HUGE_VALF; - if (__b < INT_MIN) - return __a > 0 ? 0.f : -0.f; - return scalbnf(__a, (int)__b); -} -#endif -__DEVICE__ double sin(double __a) { return __nv_sin(__a); } -__DEVICE__ void sincos(double __a, double *__s, double *__c) { - return __nv_sincos(__a, __s, __c); -} -__DEVICE__ void sincosf(float __a, float *__s, float *__c) { - return __FAST_OR_SLOW(__nv_fast_sincosf, __nv_sincosf)(__a, __s, __c); -} -__DEVICE__ void sincospi(double __a, double *__s, double *__c) { - return __nv_sincospi(__a, __s, __c); -} -__DEVICE__ void sincospif(float __a, float *__s, float *__c) { - return __nv_sincospif(__a, __s, __c); -} -__DEVICE__ float sinf(float __a) { - return __FAST_OR_SLOW(__nv_fast_sinf, __nv_sinf)(__a); -} -__DEVICE__ double sinh(double __a) { return __nv_sinh(__a); } -__DEVICE__ float sinhf(float __a) { return __nv_sinhf(__a); } -__DEVICE__ double sinpi(double __a) { return __nv_sinpi(__a); } -__DEVICE__ float sinpif(float __a) { return __nv_sinpif(__a); } -__DEVICE__ double sqrt(double __a) { return __nv_sqrt(__a); } -__DEVICE__ float sqrtf(float __a) { return __nv_sqrtf(__a); } -__DEVICE__ double tan(double __a) { return __nv_tan(__a); } -__DEVICE__ float tanf(float __a) { return __nv_tanf(__a); } -__DEVICE__ double tanh(double __a) { return __nv_tanh(__a); } -__DEVICE__ float tanhf(float __a) { return __nv_tanhf(__a); } -__DEVICE__ double tgamma(double __a) { return __nv_tgamma(__a); } -__DEVICE__ float tgammaf(float __a) { return __nv_tgammaf(__a); } -__DEVICE__ double trunc(double __a) { return __nv_trunc(__a); } -__DEVICE__ float truncf(float __a) { return __nv_truncf(__a); } -__DEVICE__ unsigned long long ullmax(unsigned long long __a, - unsigned long long __b) { - return __nv_ullmax(__a, __b); -} -__DEVICE__ unsigned long long ullmin(unsigned long long __a, - unsigned long long __b) { - return __nv_ullmin(__a, __b); -} -__DEVICE__ unsigned int umax(unsigned int __a, unsigned int __b) { - return __nv_umax(__a, __b); -} -__DEVICE__ unsigned int umin(unsigned int __a, unsigned int __b) { - return __nv_umin(__a, __b); -} -__DEVICE__ double y0(double __a) { return __nv_y0(__a); } -__DEVICE__ float y0f(float __a) { return __nv_y0f(__a); } -__DEVICE__ double y1(double __a) { return __nv_y1(__a); } -__DEVICE__ float y1f(float __a) { return __nv_y1f(__a); } -__DEVICE__ double yn(int __a, double __b) { return __nv_yn(__a, __b); } -__DEVICE__ float ynf(int __a, float __b) { return __nv_ynf(__a, __b); } -#undef __NOEXCEPT #pragma pop_macro("__DEVICE__") -#pragma pop_macro("__FAST_OR_SLOW") #endif // __CLANG_CUDA_DEVICE_FUNCTIONS_H__ diff --git a/clang/lib/Headers/__clang_cuda_math.h b/clang/lib/Headers/__clang_cuda_math.h new file mode 100644 index 0000000000000..7956135bfad59 --- /dev/null +++ b/clang/lib/Headers/__clang_cuda_math.h @@ -0,0 +1,345 @@ +/*===---- __clang_cuda_math.h - Device-side CUDA math support --------------=== + * + * 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 + * + *===-----------------------------------------------------------------------=== + */ +#ifndef __CLANG_CUDA_MATH_H__ +#define __CLANG_CUDA_MATH_H__ +#ifndef __CUDA__ +#error "This file is for CUDA compilation only." +#endif + +#ifndef _OPENMP +#if CUDA_VERSION < 9000 +#error This file is intended to be used with CUDA-9+ only. +#endif +#endif + +// __DEVICE__ is a helper macro with common set of attributes for the wrappers +// we implement in this file. We need static in order to avoid emitting unused +// functions and __forceinline__ helps inlining these wrappers at -O1. +#pragma push_macro("__DEVICE__") +#ifdef _OPENMP +#define __DEVICE__ static __inline__ __attribute__((always_inline)) +#else +#define __DEVICE__ static __device__ __forceinline__ +#endif + +// libdevice provides fast low precision and slow full-recision implementations +// for some functions. Which one gets selected depends on +// __CLANG_CUDA_APPROX_TRANSCENDENTALS__ which gets defined by clang if +// -ffast-math or -fcuda-approx-transcendentals are in effect. +#pragma push_macro("__FAST_OR_SLOW") +#if defined(__CLANG_CUDA_APPROX_TRANSCENDENTALS__) +#define __FAST_OR_SLOW(fast, slow) fast +#else +#define __FAST_OR_SLOW(fast, slow) slow +#endif + +// For C++ 17 we need to include noexcept attribute to be compatible +// with the header-defined version. This may be removed once +// variant is supported. +#if defined(_OPENMP) && defined(__cplusplus) && __cplusplus >= 201703L +#define __NOEXCEPT noexcept +#else +#define __NOEXCEPT +#endif + +__DEVICE__ int abs(int __a) __NOEXCEPT { return __nv_abs(__a); } +__DEVICE__ double fabs(double __a) __NOEXCEPT { return __nv_fabs(__a); } +__DEVICE__ double acos(double __a) { return __nv_acos(__a); } +__DEVICE__ float acosf(float __a) { return __nv_acosf(__a); } +__DEVICE__ double acosh(double __a) { return __nv_acosh(__a); } +__DEVICE__ float acoshf(float __a) { return __nv_acoshf(__a); } +__DEVICE__ double asin(double __a) { return __nv_asin(__a); } +__DEVICE__ float asinf(float __a) { return __nv_asinf(__a); } +__DEVICE__ double asinh(double __a) { return __nv_asinh(__a); } +__DEVICE__ float asinhf(float __a) { return __nv_asinhf(__a); } +__DEVICE__ double atan(double __a) { return __nv_atan(__a); } +__DEVICE__ double atan2(double __a, double __b) { return __nv_atan2(__a, __b); } +__DEVICE__ float atan2f(float __a, float __b) { return __nv_atan2f(__a, __b); } +__DEVICE__ float atanf(float __a) { return __nv_atanf(__a); } +__DEVICE__ double atanh(double __a) { return __nv_atanh(__a); } +__DEVICE__ float atanhf(float __a) { return __nv_atanhf(__a); } +__DEVICE__ double cbrt(double __a) { return __nv_cbrt(__a); } +__DEVICE__ float cbrtf(float __a) { return __nv_cbrtf(__a); } +__DEVICE__ double ceil(double __a) { return __nv_ceil(__a); } +__DEVICE__ float ceilf(float __a) { return __nv_ceilf(__a); } +__DEVICE__ double copysign(double __a, double __b) { + return __nv_copysign(__a, __b); +} +__DEVICE__ float copysignf(float __a, float __b) { + return __nv_copysignf(__a, __b); +} +__DEVICE__ double cos(double __a) { return __nv_cos(__a); } +__DEVICE__ float cosf(float __a) { + return __FAST_OR_SLOW(__nv_fast_cosf, __nv_cosf)(__a); +} +__DEVICE__ double cosh(double __a) { return __nv_cosh(__a); } +__DEVICE__ float coshf(float __a) { return __nv_coshf(__a); } +__DEVICE__ double cospi(double __a) { return __nv_cospi(__a); } +__DEVICE__ float cospif(float __a) { return __nv_cospif(__a); } +__DEVICE__ double cyl_bessel_i0(double __a) { return __nv_cyl_bessel_i0(__a); } +__DEVICE__ float cyl_bessel_i0f(float __a) { return __nv_cyl_bessel_i0f(__a); } +__DEVICE__ double cyl_bessel_i1(double __a) { return __nv_cyl_bessel_i1(__a); } +__DEVICE__ float cyl_bessel_i1f(float __a) { return __nv_cyl_bessel_i1f(__a); } +__DEVICE__ double erf(double __a) { return __nv_erf(__a); } +__DEVICE__ double erfc(double __a) { return __nv_erfc(__a); } +__DEVICE__ float erfcf(float __a) { return __nv_erfcf(__a); } +__DEVICE__ double erfcinv(double __a) { return __nv_erfcinv(__a); } +__DEVICE__ float erfcinvf(float __a) { return __nv_erfcinvf(__a); } +__DEVICE__ double erfcx(double __a) { return __nv_erfcx(__a); } +__DEVICE__ float erfcxf(float __a) { return __nv_erfcxf(__a); } +__DEVICE__ float erff(float __a) { return __nv_erff(__a); } +__DEVICE__ double erfinv(double __a) { return __nv_erfinv(__a); } +__DEVICE__ float erfinvf(float __a) { return __nv_erfinvf(__a); } +__DEVICE__ double exp(double __a) { return __nv_exp(__a); } +__DEVICE__ double exp10(double __a) { return __nv_exp10(__a); } +__DEVICE__ float exp10f(float __a) { return __nv_exp10f(__a); } +__DEVICE__ double exp2(double __a) { return __nv_exp2(__a); } +__DEVICE__ float exp2f(float __a) { return __nv_exp2f(__a); } +__DEVICE__ float expf(float __a) { return __nv_expf(__a); } +__DEVICE__ double expm1(double __a) { return __nv_expm1(__a); } +__DEVICE__ float expm1f(float __a) { return __nv_expm1f(__a); } +__DEVICE__ float fabsf(float __a) __NOEXCEPT { return __nv_fabsf(__a); } +__DEVICE__ double fdim(double __a, double __b) { return __nv_fdim(__a, __b); } +__DEVICE__ float fdimf(float __a, float __b) { return __nv_fdimf(__a, __b); } +__DEVICE__ double fdivide(double __a, double __b) { return __a / __b; } +__DEVICE__ float fdividef(float __a, float __b) { +#if __FAST_MATH__ && !__CUDA_PREC_DIV + return __nv_fast_fdividef(__a, __b); +#else + return __a / __b; +#endif +} +__DEVICE__ double floor(double __f) { return __nv_floor(__f); } +__DEVICE__ float floorf(float __f) { return __nv_floorf(__f); } +__DEVICE__ double fma(double __a, double __b, double __c) { + return __nv_fma(__a, __b, __c); +} +__DEVICE__ float fmaf(float __a, float __b, float __c) { + return __nv_fmaf(__a, __b, __c); +} +__DEVICE__ double fmax(double __a, double __b) { return __nv_fmax(__a, __b); } +__DEVICE__ float fmaxf(float __a, float __b) { return __nv_fmaxf(__a, __b); } +__DEVICE__ double fmin(double __a, double __b) { return __nv_fmin(__a, __b); } +__DEVICE__ float fminf(float __a, float __b) { return __nv_fminf(__a, __b); } +__DEVICE__ double fmod(double __a, double __b) { return __nv_fmod(__a, __b); } +__DEVICE__ float fmodf(float __a, float __b) { return __nv_fmodf(__a, __b); } +__DEVICE__ double frexp(double __a, int *__b) { return __nv_frexp(__a, __b); } +__DEVICE__ float frexpf(float __a, int *__b) { return __nv_frexpf(__a, __b); } +__DEVICE__ double hypot(double __a, double __b) { return __nv_hypot(__a, __b); } +__DEVICE__ float hypotf(float __a, float __b) { return __nv_hypotf(__a, __b); } +__DEVICE__ int ilogb(double __a) { return __nv_ilogb(__a); } +__DEVICE__ int ilogbf(float __a) { return __nv_ilogbf(__a); } +__DEVICE__ double j0(double __a) { return __nv_j0(__a); } +__DEVICE__ float j0f(float __a) { return __nv_j0f(__a); } +__DEVICE__ double j1(double __a) { return __nv_j1(__a); } +__DEVICE__ float j1f(float __a) { return __nv_j1f(__a); } +__DEVICE__ double jn(int __n, double __a) { return __nv_jn(__n, __a); } +__DEVICE__ float jnf(int __n, float __a) { return __nv_jnf(__n, __a); } +#if defined(__LP64__) || defined(_WIN64) +__DEVICE__ long labs(long __a) __NOEXCEPT { return __nv_llabs(__a); }; +#else +__DEVICE__ long labs(long __a) __NOEXCEPT { return __nv_abs(__a); }; +#endif +__DEVICE__ double ldexp(double __a, int __b) { return __nv_ldexp(__a, __b); } +__DEVICE__ float ldexpf(float __a, int __b) { return __nv_ldexpf(__a, __b); } +__DEVICE__ double lgamma(double __a) { return __nv_lgamma(__a); } +__DEVICE__ float lgammaf(float __a) { return __nv_lgammaf(__a); } +__DEVICE__ long long llabs(long long __a) __NOEXCEPT { return __nv_llabs(__a); } +__DEVICE__ long long llmax(long long __a, long long __b) { + return __nv_llmax(__a, __b); +} +__DEVICE__ long long llmin(long long __a, long long __b) { + return __nv_llmin(__a, __b); +} +__DEVICE__ long long llrint(double __a) { return __nv_llrint(__a); } +__DEVICE__ long long llrintf(float __a) { return __nv_llrintf(__a); } +__DEVICE__ long long llround(double __a) { return __nv_llround(__a); } +__DEVICE__ long long llroundf(float __a) { return __nv_llroundf(__a); } +__DEVICE__ double log(double __a) { return __nv_log(__a); } +__DEVICE__ double log10(double __a) { return __nv_log10(__a); } +__DEVICE__ float log10f(float __a) { return __nv_log10f(__a); } +__DEVICE__ double log1p(double __a) { return __nv_log1p(__a); } +__DEVICE__ float log1pf(float __a) { return __nv_log1pf(__a); } +__DEVICE__ double log2(double __a) { return __nv_log2(__a); } +__DEVICE__ float log2f(float __a) { + return __FAST_OR_SLOW(__nv_fast_log2f, __nv_log2f)(__a); +} +__DEVICE__ double logb(double __a) { return __nv_logb(__a); } +__DEVICE__ float logbf(float __a) { return __nv_logbf(__a); } +__DEVICE__ float logf(float __a) { + return __FAST_OR_SLOW(__nv_fast_logf, __nv_logf)(__a); +} +#if defined(__LP64__) || defined(_WIN64) +__DEVICE__ long lrint(double __a) { return llrint(__a); } +__DEVICE__ long lrintf(float __a) { return __float2ll_rn(__a); } +__DEVICE__ long lround(double __a) { return llround(__a); } +__DEVICE__ long lroundf(float __a) { return llroundf(__a); } +#else +__DEVICE__ long lrint(double __a) { return (long)rint(__a); } +__DEVICE__ long lrintf(float __a) { return __float2int_rn(__a); } +__DEVICE__ long lround(double __a) { return round(__a); } +__DEVICE__ long lroundf(float __a) { return roundf(__a); } +#endif +__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 nextafter(double __a, double __b) { + return __nv_nextafter(__a, __b); +} +__DEVICE__ float nextafterf(float __a, float __b) { + return __nv_nextafterf(__a, __b); +} +__DEVICE__ double norm(int __dim, const double *__t) { + return __nv_norm(__dim, __t); +} +__DEVICE__ double norm3d(double __a, double __b, double __c) { + return __nv_norm3d(__a, __b, __c); +} +__DEVICE__ float norm3df(float __a, float __b, float __c) { + return __nv_norm3df(__a, __b, __c); +} +__DEVICE__ double norm4d(double __a, double __b, double __c, double __d) { + return __nv_norm4d(__a, __b, __c, __d); +} +__DEVICE__ float norm4df(float __a, float __b, float __c, float __d) { + return __nv_norm4df(__a, __b, __c, __d); +} +__DEVICE__ double normcdf(double __a) { return __nv_normcdf(__a); } +__DEVICE__ float normcdff(float __a) { return __nv_normcdff(__a); } +__DEVICE__ double normcdfinv(double __a) { return __nv_normcdfinv(__a); } +__DEVICE__ float normcdfinvf(float __a) { return __nv_normcdfinvf(__a); } +__DEVICE__ float normf(int __dim, const float *__t) { + return __nv_normf(__dim, __t); +} +__DEVICE__ double pow(double __a, double __b) { return __nv_pow(__a, __b); } +__DEVICE__ float powf(float __a, float __b) { return __nv_powf(__a, __b); } +__DEVICE__ double powi(double __a, int __b) { return __nv_powi(__a, __b); } +__DEVICE__ float powif(float __a, int __b) { return __nv_powif(__a, __b); } +__DEVICE__ double rcbrt(double __a) { return __nv_rcbrt(__a); } +__DEVICE__ float rcbrtf(float __a) { return __nv_rcbrtf(__a); } +__DEVICE__ double remainder(double __a, double __b) { + return __nv_remainder(__a, __b); +} +__DEVICE__ float remainderf(float __a, float __b) { + return __nv_remainderf(__a, __b); +} +__DEVICE__ double remquo(double __a, double __b, int *__c) { + return __nv_remquo(__a, __b, __c); +} +__DEVICE__ float remquof(float __a, float __b, int *__c) { + return __nv_remquof(__a, __b, __c); +} +__DEVICE__ double rhypot(double __a, double __b) { + return __nv_rhypot(__a, __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); } +__DEVICE__ double rnorm(int __a, const double *__b) { + return __nv_rnorm(__a, __b); +} +__DEVICE__ double rnorm3d(double __a, double __b, double __c) { + return __nv_rnorm3d(__a, __b, __c); +} +__DEVICE__ float rnorm3df(float __a, float __b, float __c) { + return __nv_rnorm3df(__a, __b, __c); +} +__DEVICE__ double rnorm4d(double __a, double __b, double __c, double __d) { + return __nv_rnorm4d(__a, __b, __c, __d); +} +__DEVICE__ float rnorm4df(float __a, float __b, float __c, float __d) { + return __nv_rnorm4df(__a, __b, __c, __d); +} +__DEVICE__ float rnormf(int __dim, const float *__t) { + return __nv_rnormf(__dim, __t); +} +__DEVICE__ double round(double __a) { return __nv_round(__a); } +__DEVICE__ float roundf(float __a) { return __nv_roundf(__a); } +__DEVICE__ double rsqrt(double __a) { return __nv_rsqrt(__a); } +__DEVICE__ float rsqrtf(float __a) { return __nv_rsqrtf(__a); } +__DEVICE__ double scalbn(double __a, int __b) { return __nv_scalbn(__a, __b); } +__DEVICE__ float scalbnf(float __a, int __b) { return __nv_scalbnf(__a, __b); } +// TODO: remove once variant is supported +#ifndef _OPENMP +__DEVICE__ double scalbln(double __a, long __b) { + if (__b > INT_MAX) + return __a > 0 ? HUGE_VAL : -HUGE_VAL; + if (__b < INT_MIN) + return __a > 0 ? 0.0 : -0.0; + return scalbn(__a, (int)__b); +} +__DEVICE__ float scalblnf(float __a, long __b) { + if (__b > INT_MAX) + return __a > 0 ? HUGE_VALF : -HUGE_VALF; + if (__b < INT_MIN) + return __a > 0 ? 0.f : -0.f; + return scalbnf(__a, (int)__b); +} +#endif +__DEVICE__ double sin(double __a) { return __nv_sin(__a); } +__DEVICE__ void sincos(double __a, double *__s, double *__c) { + return __nv_sincos(__a, __s, __c); +} +__DEVICE__ void sincosf(float __a, float *__s, float *__c) { + return __FAST_OR_SLOW(__nv_fast_sincosf, __nv_sincosf)(__a, __s, __c); +} +__DEVICE__ void sincospi(double __a, double *__s, double *__c) { + return __nv_sincospi(__a, __s, __c); +} +__DEVICE__ void sincospif(float __a, float *__s, float *__c) { + return __nv_sincospif(__a, __s, __c); +} +__DEVICE__ float sinf(float __a) { + return __FAST_OR_SLOW(__nv_fast_sinf, __nv_sinf)(__a); +} +__DEVICE__ double sinh(double __a) { return __nv_sinh(__a); } +__DEVICE__ float sinhf(float __a) { return __nv_sinhf(__a); } +__DEVICE__ double sinpi(double __a) { return __nv_sinpi(__a); } +__DEVICE__ float sinpif(float __a) { return __nv_sinpif(__a); } +__DEVICE__ double sqrt(double __a) { return __nv_sqrt(__a); } +__DEVICE__ float sqrtf(float __a) { return __nv_sqrtf(__a); } +__DEVICE__ double tan(double __a) { return __nv_tan(__a); } +__DEVICE__ float tanf(float __a) { return __nv_tanf(__a); } +__DEVICE__ double tanh(double __a) { return __nv_tanh(__a); } +__DEVICE__ float tanhf(float __a) { return __nv_tanhf(__a); } +__DEVICE__ double tgamma(double __a) { return __nv_tgamma(__a); } +__DEVICE__ float tgammaf(float __a) { return __nv_tgammaf(__a); } +__DEVICE__ double trunc(double __a) { return __nv_trunc(__a); } +__DEVICE__ float truncf(float __a) { return __nv_truncf(__a); } +__DEVICE__ unsigned long long ullmax(unsigned long long __a, + unsigned long long __b) { + return __nv_ullmax(__a, __b); +} +__DEVICE__ unsigned long long ullmin(unsigned long long __a, + unsigned long long __b) { + return __nv_ullmin(__a, __b); +} +__DEVICE__ unsigned int umax(unsigned int __a, unsigned int __b) { + return __nv_umax(__a, __b); +} +__DEVICE__ unsigned int umin(unsigned int __a, unsigned int __b) { + return __nv_umin(__a, __b); +} +__DEVICE__ double y0(double __a) { return __nv_y0(__a); } +__DEVICE__ float y0f(float __a) { return __nv_y0f(__a); } +__DEVICE__ double y1(double __a) { return __nv_y1(__a); } +__DEVICE__ float y1f(float __a) { return __nv_y1f(__a); } +__DEVICE__ double yn(int __a, double __b) { return __nv_yn(__a, __b); } +__DEVICE__ float ynf(int __a, float __b) { return __nv_ynf(__a, __b); } + +#pragma pop_macro("__DEVICE__") +#pragma pop_macro("__FAST_OR_SLOW") +#undef __NOEXCEPT + +#endif // __CLANG_CUDA_DEVICE_FUNCTIONS_H__ diff --git a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h index e91de3c81dbdc..63404c9bdeb5c 100644 --- a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h +++ b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h @@ -83,13 +83,15 @@ #if CUDA_VERSION < 9000 #define __CUDABE__ #else +#define __CUDACC__ #define __CUDA_LIBDEVICE__ #endif // Disables definitions of device-side runtime support stubs in // cuda_device_runtime_api.h +#include "host_defines.h" +#undef __CUDACC__ #include "driver_types.h" #include "host_config.h" -#include "host_defines.h" // Temporarily replace "nv_weak" with weak, so __attribute__((nv_weak)) in // cuda_device_runtime_api.h ends up being __attribute__((weak)) which is the @@ -141,11 +143,12 @@ inline __host__ double __signbitd(double x) { // to provide our own. #include <__clang_cuda_libdevice_declares.h> -// Wrappers for many device-side standard library functions became compiler -// builtins in CUDA-9 and have been removed from the CUDA headers. Clang now -// provides its own implementation of the wrappers. +// Wrappers for many device-side standard library functions, incl. math +// functions, became compiler builtins in CUDA-9 and have been removed from the +// CUDA headers. Clang now provides its own implementation of the wrappers. #if CUDA_VERSION >= 9000 #include <__clang_cuda_device_functions.h> +#include <__clang_cuda_math.h> #endif // __THROW is redefined to be empty by device_functions_decls.h in CUDA. Clang's diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h index 4ddd64847c32e..b06c37fa08ccf 100644 --- a/clang/lib/Headers/cpuid.h +++ b/clang/lib/Headers/cpuid.h @@ -182,6 +182,7 @@ /* Features in %edx for leaf 7 sub-leaf 0 */ #define bit_AVX5124VNNIW 0x00000004 #define bit_AVX5124FMAPS 0x00000008 +#define bit_SERIALIZE 0x00004000 #define bit_PCONFIG 0x00040000 #define bit_IBT 0x00100000 diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h index edf8c42ec4914..164b1f40478dc 100644 --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -434,6 +434,10 @@ _storebe_i64(void * __P, long long __D) { #include #endif +#if !defined(_MSC_VER) || __has_feature(modules) || defined(__SERIALIZE__) +#include +#endif + #if defined(_MSC_VER) && __has_extension(gnu_asm) /* Define the default attributes for these intrinsics */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__)) diff --git a/clang/lib/Headers/openmp_wrappers/__clang_openmp_math_declares.h b/clang/lib/Headers/openmp_wrappers/__clang_openmp_math_declares.h index a422c98bf97d9..dd97faca6932c 100644 --- a/clang/lib/Headers/openmp_wrappers/__clang_openmp_math_declares.h +++ b/clang/lib/Headers/openmp_wrappers/__clang_openmp_math_declares.h @@ -26,6 +26,7 @@ #include <__clang_cuda_libdevice_declares.h> /// Provide definitions for these functions. #include <__clang_cuda_device_functions.h> +#include <__clang_cuda_math.h> #undef __CUDA__ diff --git a/clang/lib/Headers/serializeintrin.h b/clang/lib/Headers/serializeintrin.h new file mode 100644 index 0000000000000..b774e5a24a0ba --- /dev/null +++ b/clang/lib/Headers/serializeintrin.h @@ -0,0 +1,30 @@ +/*===--------------- serializeintrin.h - serialize intrinsics --------------=== + * + * 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 + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __IMMINTRIN_H +#error "Never use directly; include instead." +#endif + +#ifndef __SERIALIZEINTRIN_H +#define __SERIALIZEINTRIN_H + +/// Serialize instruction fetch and execution. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the SERIALIZE instruction. +/// +static __inline__ void +__attribute__((__always_inline__, __nodebug__, __target__("serialize"))) +_serialize (void) +{ + __builtin_ia32_serialize (); +} + +#endif /* __SERIALIZEINTRIN_H */ diff --git a/clang/lib/Headers/wasm_simd128.h b/clang/lib/Headers/wasm_simd128.h new file mode 100644 index 0000000000000..c2c57cadfdf24 --- /dev/null +++ b/clang/lib/Headers/wasm_simd128.h @@ -0,0 +1,1145 @@ +/*===---- wasm_simd128.h - WebAssembly portable SIMD intrinsics ------------=== + * + * 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 + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __WASM_SIMD128_H +#define __WASM_SIMD128_H + +#include +#include + +// User-facing type +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 + __attribute__((__vector_size__(16), __aligned__(16))); +typedef unsigned char __u8x16 + __attribute__((__vector_size__(16), __aligned__(16))); +typedef short __i16x8 __attribute__((__vector_size__(16), __aligned__(16))); +typedef unsigned short __u16x8 + __attribute__((__vector_size__(16), __aligned__(16))); +typedef int __i32x4 __attribute__((__vector_size__(16), __aligned__(16))); +typedef unsigned int __u32x4 + __attribute__((__vector_size__(16), __aligned__(16))); +typedef long long __i64x2 __attribute__((__vector_size__(16), __aligned__(16))); +typedef unsigned long long __u64x2 + __attribute__((__vector_size__(16), __aligned__(16))); +typedef float __f32x4 __attribute__((__vector_size__(16), __aligned__(16))); +typedef double __f64x2 __attribute__((__vector_size__(16), __aligned__(16))); + +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("simd128"), \ + __min_vector_width__(128))) + +#define __REQUIRE_CONSTANT(e) \ + _Static_assert(__builtin_constant_p(e), "Expected constant") + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_load(const void *__mem) { + // UB-free unaligned access copied from xmmintrin.h + struct __wasm_v128_load_struct { + __v128_u __v; + } __attribute__((__packed__, __may_alias__)); + return ((const struct __wasm_v128_load_struct *)__mem)->__v; +} + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_v8x16_load_splat(const void *__mem) { + struct __wasm_v8x16_load_splat_struct { + uint8_t __v; + } __attribute__((__packed__, __may_alias__)); + uint8_t __v = ((const struct __wasm_v8x16_load_splat_struct *)__mem)->__v; + return (v128_t)(__u8x16){__v, __v, __v, __v, __v, __v, __v, __v, + __v, __v, __v, __v, __v, __v, __v, __v}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_v16x8_load_splat(const void *__mem) { + struct __wasm_v16x8_load_splat_struct { + uint16_t __v; + } __attribute__((__packed__, __may_alias__)); + uint16_t __v = ((const struct __wasm_v16x8_load_splat_struct *)__mem)->__v; + return (v128_t)(__u16x8){__v, __v, __v, __v, __v, __v, __v, __v}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_v32x4_load_splat(const void *__mem) { + struct __wasm_v32x4_load_splat_struct { + uint32_t __v; + } __attribute__((__packed__, __may_alias__)); + uint32_t __v = ((const struct __wasm_v32x4_load_splat_struct *)__mem)->__v; + return (v128_t)(__u32x4){__v, __v, __v, __v}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_v64x2_load_splat(const void *__mem) { + struct __wasm_v64x2_load_splat_struct { + uint64_t __v; + } __attribute__((__packed__, __may_alias__)); + uint64_t __v = ((const struct __wasm_v64x2_load_splat_struct *)__mem)->__v; + return (v128_t)(__u64x2){__v, __v}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_load_8x8(const void *__mem) { + typedef int8_t __i8x8 __attribute__((__vector_size__(8), __aligned__(8))); + struct __wasm_i16x8_load_8x8_struct { + __i8x8 __v; + } __attribute__((__packed__, __may_alias__)); + __i8x8 __v = ((const struct __wasm_i16x8_load_8x8_struct *)__mem)->__v; + return (v128_t) __builtin_convertvector(__v, __i16x8); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u16x8_load_8x8(const void *__mem) { + typedef uint8_t __u8x8 __attribute__((__vector_size__(8), __aligned__(8))); + struct __wasm_u16x8_load_8x8_struct { + __u8x8 __v; + } __attribute__((__packed__, __may_alias__)); + __u8x8 __v = ((const struct __wasm_u16x8_load_8x8_struct *)__mem)->__v; + return (v128_t) __builtin_convertvector(__v, __u16x8); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i32x4_load_16x4(const void *__mem) { + typedef int16_t __i16x4 __attribute__((__vector_size__(8), __aligned__(8))); + struct __wasm_i32x4_load_16x4_struct { + __i16x4 __v; + } __attribute__((__packed__, __may_alias__)); + __i16x4 __v = ((const struct __wasm_i32x4_load_16x4_struct *)__mem)->__v; + return (v128_t) __builtin_convertvector(__v, __i32x4); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u32x4_load_16x4(const void *__mem) { + typedef uint16_t __u16x4 __attribute__((__vector_size__(8), __aligned__(8))); + struct __wasm_u32x4_load_16x4_struct { + __u16x4 __v; + } __attribute__((__packed__, __may_alias__)); + __u16x4 __v = ((const struct __wasm_u32x4_load_16x4_struct *)__mem)->__v; + return (v128_t) __builtin_convertvector(__v, __u32x4); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i64x2_load_32x2(const void *__mem) { + typedef int32_t __i32x2 __attribute__((__vector_size__(8), __aligned__(8))); + struct __wasm_i64x2_load_32x2_struct { + __i32x2 __v; + } __attribute__((__packed__, __may_alias__)); + __i32x2 __v = ((const struct __wasm_i64x2_load_32x2_struct *)__mem)->__v; + return (v128_t) __builtin_convertvector(__v, __i64x2); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u64x2_load_32x2(const void *__mem) { + typedef uint32_t __u32x2 __attribute__((__vector_size__(8), __aligned__(8))); + struct __wasm_u64x2_load_32x2_struct { + __u32x2 __v; + } __attribute__((__packed__, __may_alias__)); + __u32x2 __v = ((const struct __wasm_u64x2_load_32x2_struct *)__mem)->__v; + return (v128_t) __builtin_convertvector(__v, __u64x2); +} + +#endif // __wasm_unimplemented_simd128__ + +static __inline__ void __DEFAULT_FN_ATTRS wasm_v128_store(void *__mem, + v128_t __a) { + // UB-free unaligned access copied from xmmintrin.h + struct __wasm_v128_store_struct { + __v128_u __v; + } __attribute__((__packed__, __may_alias__)); + ((struct __wasm_v128_store_struct *)__mem)->__v = __a; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i8x16_make(int8_t __c0, int8_t __c1, int8_t __c2, int8_t __c3, int8_t __c4, + int8_t __c5, int8_t __c6, int8_t __c7, int8_t __c8, int8_t __c9, + int8_t __c10, int8_t __c11, int8_t __c12, int8_t __c13, + int8_t __c14, int8_t __c15) { + return (v128_t)(__i8x16){__c0, __c1, __c2, __c3, __c4, __c5, + __c6, __c7, __c8, __c9, __c10, __c11, + __c12, __c13, __c14, __c15}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_make(int16_t __c0, int16_t __c1, int16_t __c2, int16_t __c3, + int16_t __c4, int16_t __c5, int16_t __c6, int16_t __c7) { + return (v128_t)(__i16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_make(int32_t __c0, + int32_t __c1, + int32_t __c2, + int32_t __c3) { + return (v128_t)(__i32x4){__c0, __c1, __c2, __c3}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_make(float __c0, + float __c1, + float __c2, + float __c3) { + return (v128_t)(__f32x4){__c0, __c1, __c2, __c3}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_make(int64_t __c0, + int64_t __c1) { + return (v128_t)(__i64x2){__c0, __c1}; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_make(double __c0, + double __c1) { + return (v128_t)(__f64x2){__c0, __c1}; +} + +#define wasm_i8x16_const(__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7, __c8, \ + __c9, __c10, __c11, __c12, __c13, __c14, __c15) \ + __extension__({ \ + __REQUIRE_CONSTANT(__c0); \ + __REQUIRE_CONSTANT(__c1); \ + __REQUIRE_CONSTANT(__c2); \ + __REQUIRE_CONSTANT(__c3); \ + __REQUIRE_CONSTANT(__c4); \ + __REQUIRE_CONSTANT(__c5); \ + __REQUIRE_CONSTANT(__c6); \ + __REQUIRE_CONSTANT(__c7); \ + __REQUIRE_CONSTANT(__c8); \ + __REQUIRE_CONSTANT(__c9); \ + __REQUIRE_CONSTANT(__c10); \ + __REQUIRE_CONSTANT(__c11); \ + __REQUIRE_CONSTANT(__c12); \ + __REQUIRE_CONSTANT(__c13); \ + __REQUIRE_CONSTANT(__c14); \ + __REQUIRE_CONSTANT(__c15); \ + (v128_t)(__i8x16){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7, \ + __c8, __c9, __c10, __c11, __c12, __c13, __c14, __c15}; \ + }) + +#define wasm_i16x8_const(__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7) \ + __extension__({ \ + __REQUIRE_CONSTANT(__c0); \ + __REQUIRE_CONSTANT(__c1); \ + __REQUIRE_CONSTANT(__c2); \ + __REQUIRE_CONSTANT(__c3); \ + __REQUIRE_CONSTANT(__c4); \ + __REQUIRE_CONSTANT(__c5); \ + __REQUIRE_CONSTANT(__c6); \ + __REQUIRE_CONSTANT(__c7); \ + (v128_t)(__i16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7}; \ + }) + +#define wasm_i32x4_const(__c0, __c1, __c2, __c3) \ + __extension__({ \ + __REQUIRE_CONSTANT(__c0); \ + __REQUIRE_CONSTANT(__c1); \ + __REQUIRE_CONSTANT(__c2); \ + __REQUIRE_CONSTANT(__c3); \ + (v128_t)(__i32x4){__c0, __c1, __c2, __c3}; \ + }) + +#define wasm_f32x4_const(__c0, __c1, __c2, __c3) \ + __extension__({ \ + __REQUIRE_CONSTANT(__c0); \ + __REQUIRE_CONSTANT(__c1); \ + __REQUIRE_CONSTANT(__c2); \ + __REQUIRE_CONSTANT(__c3); \ + (v128_t)(__f32x4){__c0, __c1, __c2, __c3}; \ + }) + +#define wasm_i64x2_const(__c0, __c1) \ + __extension__({ \ + __REQUIRE_CONSTANT(__c0); \ + __REQUIRE_CONSTANT(__c1); \ + (v128_t)(__i64x2){__c0, __c1}; \ + }) + +#define wasm_f64x2_const(__c0, __c1) \ + __extension__({ \ + __REQUIRE_CONSTANT(__c0); \ + __REQUIRE_CONSTANT(__c1); \ + (v128_t)(__f64x2){__c0, __c1}; \ + }) + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_splat(int8_t __a) { + return (v128_t)(__i8x16){__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; +} + +#define wasm_i8x16_extract_lane(__a, __i) \ + (__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)) + +#define wasm_i8x16_replace_lane(__a, __i, __b) \ + ((v128_t)__builtin_wasm_replace_lane_i8x16((__i8x16)(__a), __i, __b)) + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_splat(int16_t __a) { + return (v128_t)(__i16x8){__a, __a, __a, __a, __a, __a, __a, __a}; +} + +#define wasm_i16x8_extract_lane(__a, __i) \ + (__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)) + +#define wasm_i16x8_replace_lane(__a, __i, __b) \ + ((v128_t)__builtin_wasm_replace_lane_i16x8((__i16x8)(__a), __i, __b)) + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_splat(int32_t __a) { + return (v128_t)(__i32x4){__a, __a, __a, __a}; +} + +#define wasm_i32x4_extract_lane(__a, __i) \ + (__builtin_wasm_extract_lane_i32x4((__i32x4)(__a), __i)) + +#define wasm_i32x4_replace_lane(__a, __i, __b) \ + ((v128_t)__builtin_wasm_replace_lane_i32x4((__i32x4)(__a), __i, __b)) + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_splat(int64_t __a) { + return (v128_t)(__i64x2){__a, __a}; +} + +#define wasm_i64x2_extract_lane(__a, __i) \ + (__builtin_wasm_extract_lane_i64x2((__i64x2)(__a), __i)) + +#define wasm_i64x2_replace_lane(__a, __i, __b) \ + ((v128_t)__builtin_wasm_replace_lane_i64x2((__i64x2)(__a), __i, __b)) + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_splat(float __a) { + return (v128_t)(__f32x4){__a, __a, __a, __a}; +} + +#define wasm_f32x4_extract_lane(__a, __i) \ + (__builtin_wasm_extract_lane_f32x4((__f32x4)(__a), __i)) + +#define wasm_f32x4_replace_lane(__a, __i, __b) \ + ((v128_t)__builtin_wasm_replace_lane_f32x4((__f32x4)(__a), __i, __b)) + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_splat(double __a) { + return (v128_t)(__f64x2){__a, __a}; +} + +#define wasm_f64x2_extract_lane(__a, __i) \ + (__builtin_wasm_extract_lane_f64x2((__f64x2)(__a), __i)) + +#define wasm_f64x2_replace_lane(__a, __i, __b) \ + ((v128_t)__builtin_wasm_replace_lane_f64x2((__f64x2)(__a), __i, __b)) + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_eq(v128_t __a, + v128_t __b) { + return (v128_t)((__s8x16)__a == (__s8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_ne(v128_t __a, + v128_t __b) { + return (v128_t)((__s8x16)__a != (__s8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__s8x16)__a < (__s8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__u8x16)__a < (__u8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__s8x16)__a > (__s8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__u8x16)__a > (__u8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_le(v128_t __a, + v128_t __b) { + return (v128_t)((__s8x16)__a <= (__s8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_le(v128_t __a, + v128_t __b) { + return (v128_t)((__u8x16)__a <= (__u8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__s8x16)__a >= (__s8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__u8x16)__a >= (__u8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_eq(v128_t __a, + v128_t __b) { + return (v128_t)((__i16x8)__a == (__i16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_ne(v128_t __a, + v128_t __b) { + return (v128_t)((__u16x8)__a != (__u16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__i16x8)__a < (__i16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__u16x8)__a < (__u16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__i16x8)__a > (__i16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__u16x8)__a > (__u16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_le(v128_t __a, + v128_t __b) { + return (v128_t)((__i16x8)__a <= (__i16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_le(v128_t __a, + v128_t __b) { + return (v128_t)((__u16x8)__a <= (__u16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__i16x8)__a >= (__i16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__u16x8)__a >= (__u16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_eq(v128_t __a, + v128_t __b) { + return (v128_t)((__i32x4)__a == (__i32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_ne(v128_t __a, + v128_t __b) { + return (v128_t)((__i32x4)__a != (__i32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__i32x4)__a < (__i32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__u32x4)__a < (__u32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__i32x4)__a > (__i32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__u32x4)__a > (__u32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_le(v128_t __a, + v128_t __b) { + return (v128_t)((__i32x4)__a <= (__i32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_le(v128_t __a, + v128_t __b) { + return (v128_t)((__u32x4)__a <= (__u32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__i32x4)__a >= (__i32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__u32x4)__a >= (__u32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_eq(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a == (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_ne(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a != (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a < (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a > (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_le(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a <= (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a >= (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_eq(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a == (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_ne(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a != (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_lt(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a < (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_gt(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a > (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_le(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a <= (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_ge(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a >= (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_not(v128_t __a) { + return ~__a; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_and(v128_t __a, + v128_t __b) { + return __a & __b; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_or(v128_t __a, + v128_t __b) { + return __a | __b; +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_xor(v128_t __a, + v128_t __b) { + return __a ^ __b; +} + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_andnot(v128_t __a, + v128_t __b) { + return __a & ~__b; +} + +#endif // __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v128_bitselect(v128_t __a, + v128_t __b, + v128_t __mask) { + return (v128_t)__builtin_wasm_bitselect((__i32x4)__a, (__i32x4)__b, + (__i32x4)__mask); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_abs(v128_t __a) { + return (v128_t)__builtin_wasm_abs_i8x16((__i8x16)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_neg(v128_t __a) { + return (v128_t)(-(__u8x16)__a); +} + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i8x16_any_true(v128_t __a) { + return __builtin_wasm_any_true_i8x16((__i8x16)__a); +} + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i8x16_all_true(v128_t __a) { + return __builtin_wasm_all_true_i8x16((__i8x16)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_shl(v128_t __a, + int32_t __b) { + return (v128_t)((__i8x16)__a << __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__s8x16)__a >> __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__u8x16)__a >> __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_add(v128_t __a, + v128_t __b) { + return (v128_t)((__u8x16)__a + (__u8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i8x16_add_saturate(v128_t __a, v128_t __b) { + return (v128_t)__builtin_wasm_add_saturate_s_i8x16((__i8x16)__a, + (__i8x16)__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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_sub(v128_t __a, + v128_t __b) { + return (v128_t)((__u8x16)__a - (__u8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i8x16_sub_saturate(v128_t __a, v128_t __b) { + return (v128_t)__builtin_wasm_sub_saturate_s_i8x16((__i8x16)__a, + (__i8x16)__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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_mul(v128_t __a, + v128_t __b) { + return (v128_t)((__u8x16)__a * (__u8x16)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_min(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_min_s_i8x16((__i8x16)__a, (__i8x16)__b); +} + +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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_max(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_max_s_i8x16((__i8x16)__a, (__i8x16)__b); +} + +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); +} + +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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_abs(v128_t __a) { + return (v128_t)__builtin_wasm_abs_i16x8((__i16x8)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_neg(v128_t __a) { + return (v128_t)(-(__u16x8)__a); +} + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i16x8_any_true(v128_t __a) { + return __builtin_wasm_any_true_i16x8((__i16x8)__a); +} + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i16x8_all_true(v128_t __a) { + return __builtin_wasm_all_true_i16x8((__i16x8)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_shl(v128_t __a, + int32_t __b) { + return (v128_t)((__i16x8)__a << __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__i16x8)__a >> __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__u16x8)__a >> __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_add(v128_t __a, + v128_t __b) { + return (v128_t)((__u16x8)__a + (__u16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_add_saturate(v128_t __a, v128_t __b) { + return (v128_t)__builtin_wasm_add_saturate_s_i16x8((__i16x8)__a, + (__i16x8)__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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_sub(v128_t __a, + v128_t __b) { + return (v128_t)((__i16x8)__a - (__i16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_sub_saturate(v128_t __a, v128_t __b) { + return (v128_t)__builtin_wasm_sub_saturate_s_i16x8((__i16x8)__a, + (__i16x8)__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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_mul(v128_t __a, + v128_t __b) { + return (v128_t)((__u16x8)__a * (__u16x8)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_min(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_min_s_i16x8((__i16x8)__a, (__i16x8)__b); +} + +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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_max(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_max_s_i16x8((__i16x8)__a, (__i16x8)__b); +} + +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); +} + +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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_abs(v128_t __a) { + return (v128_t)__builtin_wasm_abs_i32x4((__i32x4)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_neg(v128_t __a) { + return (v128_t)(-(__u32x4)__a); +} + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i32x4_any_true(v128_t __a) { + return __builtin_wasm_any_true_i32x4((__i32x4)__a); +} + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i32x4_all_true(v128_t __a) { + return __builtin_wasm_all_true_i32x4((__i32x4)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_shl(v128_t __a, + int32_t __b) { + return (v128_t)((__i32x4)__a << __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__i32x4)__a >> __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__u32x4)__a >> __b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_add(v128_t __a, + v128_t __b) { + return (v128_t)((__u32x4)__a + (__u32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_sub(v128_t __a, + v128_t __b) { + return (v128_t)((__u32x4)__a - (__u32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_mul(v128_t __a, + v128_t __b) { + return (v128_t)((__u32x4)__a * (__u32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_min(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_min_s_i32x4((__i32x4)__a, (__i32x4)__b); +} + +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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_max(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_max_s_i32x4((__i32x4)__a, (__i32x4)__b); +} + +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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_neg(v128_t __a) { + return (v128_t)(-(__u64x2)__a); +} + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i64x2_any_true(v128_t __a) { + return __builtin_wasm_any_true_i64x2((__i64x2)__a); +} + +static __inline__ bool __DEFAULT_FN_ATTRS wasm_i64x2_all_true(v128_t __a) { + return __builtin_wasm_all_true_i64x2((__i64x2)__a); +} + +#endif // __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_shl(v128_t __a, + int32_t __b) { + return (v128_t)((__i64x2)__a << (int64_t)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__i64x2)__a >> (int64_t)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u64x2_shr(v128_t __a, + int32_t __b) { + return (v128_t)((__u64x2)__a >> (int64_t)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_add(v128_t __a, + v128_t __b) { + return (v128_t)((__u64x2)__a + (__u64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_sub(v128_t __a, + v128_t __b) { + return (v128_t)((__u64x2)__a - (__u64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_abs(v128_t __a) { + return (v128_t)__builtin_wasm_abs_f32x4((__f32x4)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_neg(v128_t __a) { + return (v128_t)(-(__f32x4)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_sqrt(v128_t __a) { + return (v128_t)__builtin_wasm_sqrt_f32x4((__f32x4)__a); +} + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_qfma(v128_t __a, + v128_t __b, + v128_t __c) { + return (v128_t)__builtin_wasm_qfma_f32x4((__f32x4)__a, (__f32x4)__b, + (__f32x4)__c); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_qfms(v128_t __a, + v128_t __b, + v128_t __c) { + return (v128_t)__builtin_wasm_qfms_f32x4((__f32x4)__a, (__f32x4)__b, + (__f32x4)__c); +} + +#endif // __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_add(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a + (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_sub(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a - (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_mul(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a * (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_div(v128_t __a, + v128_t __b) { + return (v128_t)((__f32x4)__a / (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_min(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_min_f32x4((__f32x4)__a, (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_max(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_max_f32x4((__f32x4)__a, (__f32x4)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_abs(v128_t __a) { + return (v128_t)__builtin_wasm_abs_f64x2((__f64x2)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_neg(v128_t __a) { + return (v128_t)(-(__f64x2)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_sqrt(v128_t __a) { + return (v128_t)__builtin_wasm_sqrt_f64x2((__f64x2)__a); +} + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_qfma(v128_t __a, + v128_t __b, + v128_t __c) { + return (v128_t)__builtin_wasm_qfma_f64x2((__f64x2)__a, (__f64x2)__b, + (__f64x2)__c); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_qfms(v128_t __a, + v128_t __b, + v128_t __c) { + return (v128_t)__builtin_wasm_qfms_f64x2((__f64x2)__a, (__f64x2)__b, + (__f64x2)__c); +} + +#endif // __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_add(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a + (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_sub(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a - (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_mul(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a * (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_div(v128_t __a, + v128_t __b) { + return (v128_t)((__f64x2)__a / (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_min(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_min_f64x2((__f64x2)__a, (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_max(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_max_f64x2((__f64x2)__a, (__f64x2)__b); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i32x4_trunc_saturate_f32x4(v128_t __a) { + return (v128_t)__builtin_wasm_trunc_saturate_s_i32x4_f32x4((__f32x4)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u32x4_trunc_saturate_f32x4(v128_t __a) { + return (v128_t)__builtin_wasm_trunc_saturate_u_i32x4_f32x4((__f32x4)__a); +} + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i64x2_trunc_saturate_f64x2(v128_t __a) { + return (v128_t)__builtin_wasm_trunc_saturate_s_i64x2_f64x2((__f64x2)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u64x2_trunc_saturate_f64x2(v128_t __a) { + return (v128_t)__builtin_wasm_trunc_saturate_s_i64x2_f64x2((__f64x2)__a); +} + +#endif // __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_f32x4_convert_i32x4(v128_t __a) { + return (v128_t) __builtin_convertvector((__i32x4)__a, __f32x4); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_f32x4_convert_u32x4(v128_t __a) { + return (v128_t) __builtin_convertvector((__u32x4)__a, __f32x4); +} + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_f64x2_convert_i64x2(v128_t __a) { + return (v128_t) __builtin_convertvector((__i64x2)__a, __f64x2); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_f64x2_convert_u64x2(v128_t __a) { + return (v128_t) __builtin_convertvector((__u64x2)__a, __f64x2); +} + +#endif // __wasm_unimplemented_simd128__ + +#define wasm_v8x16_shuffle(__a, __b, __c0, __c1, __c2, __c3, __c4, __c5, __c6, \ + __c7, __c8, __c9, __c10, __c11, __c12, __c13, \ + __c14, __c15) \ + ((v128_t)(__builtin_shufflevector( \ + (__u8x16)(__a), (__u8x16)(__b), __c0, __c1, __c2, __c3, __c4, __c5, \ + __c6, __c7, __c8, __c9, __c10, __c11, __c12, __c13, __c14, __c15))) + +#define wasm_v16x8_shuffle(__a, __b, __c0, __c1, __c2, __c3, __c4, __c5, __c6, \ + __c7) \ + ((v128_t)(__builtin_shufflevector((__u16x8)(__a), (__u16x8)(__b), __c0, \ + __c1, __c2, __c3, __c4, __c5, __c6, \ + __c7))) + +#define wasm_v32x4_shuffle(__a, __b, __c0, __c1, __c2, __c3) \ + ((v128_t)(__builtin_shufflevector((__u32x4)(__a), (__u32x4)(__b), __c0, \ + __c1, __c2, __c3))) + +#define wasm_v64x2_shuffle(__a, __b, __c0, __c1) \ + ((v128_t)( \ + __builtin_shufflevector((__u64x2)(__a), (__u64x2)(__b), __c0, __c1))) + +#ifdef __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_v8x16_swizzle(v128_t __a, + v128_t __b) { + return (v128_t)__builtin_wasm_swizzle_v8x16((__i8x16)__a, (__i8x16)__b); +} + +#endif // __wasm_unimplemented_simd128__ + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i8x16_narrow_i16x8(v128_t __a, v128_t __b) { + return (v128_t)__builtin_wasm_narrow_s_i8x16_i16x8((__i16x8)__a, + (__i16x8)__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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_narrow_i32x4(v128_t __a, v128_t __b) { + return (v128_t)__builtin_wasm_narrow_s_i16x8_i32x4((__i32x4)__a, + (__i32x4)__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); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_widen_low_i8x16(v128_t __a) { + return (v128_t)__builtin_wasm_widen_low_s_i16x8_i8x16((__i8x16)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_widen_high_i8x16(v128_t __a) { + return (v128_t)__builtin_wasm_widen_high_s_i16x8_i8x16((__i8x16)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_widen_low_u8x16(v128_t __a) { + return (v128_t)__builtin_wasm_widen_low_u_i16x8_i8x16((__i8x16)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i16x8_widen_high_u8x16(v128_t __a) { + return (v128_t)__builtin_wasm_widen_high_u_i16x8_i8x16((__i8x16)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i32x4_widen_low_i16x8(v128_t __a) { + return (v128_t)__builtin_wasm_widen_low_s_i32x4_i16x8((__i16x8)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i32x4_widen_high_i16x8(v128_t __a) { + return (v128_t)__builtin_wasm_widen_high_s_i32x4_i16x8((__i16x8)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i32x4_widen_low_u16x8(v128_t __a) { + return (v128_t)__builtin_wasm_widen_low_u_i32x4_i16x8((__i16x8)__a); +} + +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_i32x4_widen_high_u16x8(v128_t __a) { + return (v128_t)__builtin_wasm_widen_high_u_i32x4_i16x8((__i16x8)__a); +} + +// Undefine helper macros +#undef __DEFAULT_FN_ATTRS + +#endif // __WASM_SIMD128_H diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index a51745697b115..f0d2d4332b373 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -29,6 +29,7 @@ #include "clang/Basic/TokenKinds.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringRef.h" @@ -2092,7 +2093,8 @@ void Lexer::codeCompleteIncludedFile(const char *PathStart, bool IsAngled) { // Completion only applies to the filename, after the last slash. StringRef PartialPath(PathStart, CompletionPoint - PathStart); - auto Slash = PartialPath.find_last_of(LangOpts.MSVCCompat ? "/\\" : "/"); + llvm::StringRef SlashChars = LangOpts.MSVCCompat ? "/\\" : "/"; + auto Slash = PartialPath.find_last_of(SlashChars); StringRef Dir = (Slash == StringRef::npos) ? "" : PartialPath.take_front(Slash); const char *StartOfFilename = @@ -2100,7 +2102,8 @@ void Lexer::codeCompleteIncludedFile(const char *PathStart, // Code completion filter range is the filename only, up to completion point. PP->setCodeCompletionIdentifierInfo(&PP->getIdentifierTable().get( StringRef(StartOfFilename, CompletionPoint - StartOfFilename))); - // We should replace the characters up to the closing quote, if any. + // We should replace the characters up to the closing quote or closest slash, + // if any. while (CompletionPoint < BufferEnd) { char Next = *(CompletionPoint + 1); if (Next == 0 || Next == '\r' || Next == '\n') @@ -2108,7 +2111,10 @@ void Lexer::codeCompleteIncludedFile(const char *PathStart, ++CompletionPoint; if (Next == (IsAngled ? '>' : '"')) break; + if (llvm::is_contained(SlashChars, Next)) + break; } + PP->setCodeCompletionTokenRange( FileLoc.getLocWithOffset(StartOfFilename - BufferStart), FileLoc.getLocWithOffset(CompletionPoint - BufferStart)); diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index a75965784168c..06e02ed0e11c6 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -1114,17 +1114,14 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, break; } + // Put the token stream back and undo any annotations we performed + // after the comma. They may reflect a different parse than the one + // we will actually perform at the end of the class. + PA.RevertAnnotations(); + // If what follows could be a declaration, it is a declaration. - if (Result != TPResult::False && Result != TPResult::Error) { - PA.Revert(); + if (Result != TPResult::False && Result != TPResult::Error) return true; - } - - // In the uncommon case that we decide the following tokens are part - // of a template argument, revert any annotations we've performed in - // those tokens. We're not going to look them up until we've parsed - // the rest of the class, and that might add more declarations. - PA.RevertAnnotations(); } // Keep going. We know we're inside a template argument list now. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index b7cfe21da95d4..dde48bb64c961 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3163,9 +3163,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // We are looking for a qualified typename. Token Next = NextToken(); - if (Next.is(tok::annot_template_id) && - static_cast(Next.getAnnotationValue()) - ->Kind == TNK_Type_template) { + + TemplateIdAnnotation *TemplateId = Next.is(tok::annot_template_id) + ? takeTemplateIdAnnotation(Next) + : nullptr; + if (TemplateId && TemplateId->hasInvalidName()) { + // We found something like 'T::U x', but U is not a template. + // Assume it was supposed to be a type. + DS.SetTypeSpecError(); + ConsumeAnnotationToken(); + break; + } + + if (TemplateId && TemplateId->Kind == TNK_Type_template) { // We have a qualified template-id, e.g., N::A // If this would be a valid constructor declaration with template @@ -3175,7 +3185,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // // To improve diagnostics for this case, parse the declaration as a // constructor (and reject the extra template arguments later). - TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if ((DSContext == DeclSpecContext::DSC_top_level || DSContext == DeclSpecContext::DSC_class) && TemplateId->Name && @@ -3196,9 +3205,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } - if (Next.is(tok::annot_template_id) && - static_cast(Next.getAnnotationValue()) - ->Kind == TNK_Concept_template && + if (TemplateId && TemplateId->Kind == TNK_Concept_template && GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype)) { DS.getTypeSpecScope() = SS; // This is a qualified placeholder-specifier, e.g., ::C auto ... @@ -3211,16 +3218,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (Next.is(tok::annot_typename)) { DS.getTypeSpecScope() = SS; ConsumeAnnotationToken(); // The C++ scope. - if (Tok.getAnnotationValue()) { - ParsedType T = getTypeAnnotation(Tok); - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, - Tok.getAnnotationEndLoc(), - PrevSpec, DiagID, T, Policy); - if (isInvalid) - break; - } - else - DS.SetTypeSpecError(); + TypeResult T = getTypeAnnotation(Tok); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, + Tok.getAnnotationEndLoc(), + PrevSpec, DiagID, T, Policy); + if (isInvalid) + break; DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeAnnotationToken(); // The typename } @@ -3288,13 +3291,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, if (DS.hasTypeSpecifier() && DS.hasTagDefinition()) goto DoneWithDeclSpec; - if (Tok.getAnnotationValue()) { - ParsedType T = getTypeAnnotation(Tok); - isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, - DiagID, T, Policy); - } else - DS.SetTypeSpecError(); - + TypeResult T = getTypeAnnotation(Tok); + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, + DiagID, T, Policy); if (isInvalid) break; @@ -3460,7 +3459,18 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // type-name or placeholder-specifier case tok::annot_template_id: { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + + if (TemplateId->hasInvalidName()) { + DS.SetTypeSpecError(); + break; + } + if (TemplateId->Kind == TNK_Concept_template) { + // If we've already diagnosed that this type-constraint has invalid + // arguemnts, drop it and just form 'auto' or 'decltype(auto)'. + if (TemplateId->hasInvalidArgs()) + TemplateId = nullptr; + if (NextToken().is(tok::identifier)) { Diag(Loc, diag::err_placeholder_expected_auto_or_decltype_auto) << FixItHint::CreateInsertion(NextToken().getLocation(), "auto"); @@ -5198,14 +5208,30 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // placeholder-type-specifier case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->hasInvalidName()) + return true; + // FIXME: What about type templates that have only been annotated as + // annot_template_id, not as annot_typename? return isTypeConstraintAnnotation() && - (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); + (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); } - case tok::annot_cxxscope: + + case tok::annot_cxxscope: { + TemplateIdAnnotation *TemplateId = + NextToken().is(tok::annot_template_id) + ? takeTemplateIdAnnotation(NextToken()) + : nullptr; + if (TemplateId && TemplateId->hasInvalidName()) + return true; + // FIXME: What about type templates that have only been annotated as + // annot_template_id, not as annot_typename? if (NextToken().is(tok::identifier) && TryAnnotateTypeConstraint()) return true; return isTypeConstraintAnnotation() && GetLookAheadToken(2).isOneOf(tok::kw_auto, tok::kw_decltype); + } + case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 86a9a8208b2eb..710632379ace9 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1147,19 +1147,14 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - if (TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name || - TemplateId->Kind == TNK_Undeclared_template) { + if (TemplateId->mightBeType()) { AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); - ParsedType Type = getTypeAnnotation(Tok); + TypeResult Type = getTypeAnnotation(Tok); EndLocation = Tok.getAnnotationEndLoc(); ConsumeAnnotationToken(); - - if (Type) - return Type; - return true; + return Type; } // Fall through to produce an error below. @@ -1176,7 +1171,9 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, if (Tok.is(tok::less)) { // It looks the user intended to write a template-id here, but the // template-name was wrong. Try to fix that. - TemplateNameKind TNK = TNK_Type_template; + // FIXME: Invoke ParseOptionalCXXScopeSpecifier in a "'template' is neither + // required nor permitted" mode, and do this there. + TemplateNameKind TNK = TNK_Non_template; TemplateTy Template; if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(), &SS, Template, TNK)) { @@ -1184,14 +1181,6 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, << Id; } - if (!Template) { - TemplateArgList TemplateArgs; - SourceLocation LAngleLoc, RAngleLoc; - ParseTemplateIdAfterTemplateName(true, LAngleLoc, TemplateArgs, - RAngleLoc); - return true; - } - // Form the template name UnqualifiedId TemplateName; TemplateName.setIdentifier(Id, IdLoc); @@ -1200,7 +1189,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName)) return true; - if (TNK == TNK_Type_template || TNK == TNK_Dependent_template_name) + if (Tok.is(tok::annot_template_id) && + takeTemplateIdAnnotation(Tok)->mightBeType()) AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true); // If we didn't end up with a typename token, there's nothing more we @@ -1211,7 +1201,7 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc, // Retrieve the type from the annotation token, consume that token, and // return. EndLocation = Tok.getAnnotationEndLoc(); - ParsedType Type = getTypeAnnotation(Tok); + TypeResult Type = getTypeAnnotation(Tok); ConsumeAnnotationToken(); return Type; } @@ -1630,9 +1620,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, NameLoc = ConsumeAnnotationToken(); if (TemplateId->Kind == TNK_Undeclared_template) { - // Try to resolve the template name to a type template. - Actions.ActOnUndeclaredTypeTemplateName(getCurScope(), TemplateId->Template, - TemplateId->Kind, NameLoc, Name); + // Try to resolve the template name to a type template. May update Kind. + Actions.ActOnUndeclaredTypeTemplateName( + getCurScope(), TemplateId->Template, TemplateId->Kind, NameLoc, Name); if (TemplateId->Kind == TNK_Undeclared_template) { RecoverFromUndeclaredTemplateName( Name, NameLoc, @@ -1641,10 +1631,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } - if (TemplateId && TemplateId->Kind != TNK_Type_template && - TemplateId->Kind != TNK_Dependent_template_name) { + if (TemplateId && !TemplateId->mightBeType()) { // The template-name in the simple-template-id refers to - // something other than a class template. Give an appropriate + // something other than a type template. Give an appropriate // error message and skip to the ';'. SourceRange Range(NameLoc); if (SS.isNotEmpty()) @@ -1816,7 +1805,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // or explicit instantiation. ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); - if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && + if (TemplateId->isInvalid()) { + // Can't build the declaration. + } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { // This is an explicit instantiation of a class template. ProhibitAttributes(attrs); @@ -3516,7 +3507,7 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // : declype(...) DeclSpec DS(AttrFactory); // : template_name<...> - ParsedType TemplateTypeTy; + TypeResult TemplateTypeTy; if (Tok.is(tok::identifier)) { // Get the identifier. This may be a member name or a class name, @@ -3533,15 +3524,11 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { TemplateIdAnnotation *TemplateId = Tok.is(tok::annot_template_id) ? takeTemplateIdAnnotation(Tok) : nullptr; - if (TemplateId && (TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name || - TemplateId->Kind == TNK_Undeclared_template)) { + if (TemplateId && TemplateId->mightBeType()) { AnnotateTemplateIdTokenAsType(SS, /*IsClassName*/true); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); TemplateTypeTy = getTypeAnnotation(Tok); ConsumeAnnotationToken(); - if (!TemplateTypeTy) - return true; } else { Diag(Tok, diag::err_expected_member_or_base_name); return true; @@ -3560,8 +3547,10 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { SourceLocation EllipsisLoc; TryConsumeToken(tok::ellipsis, EllipsisLoc); + if (TemplateTypeTy.isInvalid()) + return true; return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, DS, IdLoc, + TemplateTypeTy.get(), DS, IdLoc, InitList.get(), EllipsisLoc); } else if(Tok.is(tok::l_paren)) { BalancedDelimiterTracker T(*this, tok::l_paren); @@ -3571,8 +3560,10 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { ExprVector ArgExprs; CommaLocsTy CommaLocs; auto RunSignatureHelp = [&] { + if (TemplateTypeTy.isInvalid()) + return QualType(); QualType PreferredType = Actions.ProduceCtorInitMemberSignatureHelp( - getCurScope(), ConstructorDecl, SS, TemplateTypeTy, ArgExprs, II, + getCurScope(), ConstructorDecl, SS, TemplateTypeTy.get(), ArgExprs, II, T.getOpenLocation()); CalledSignatureHelp = true; return PreferredType; @@ -3593,12 +3584,17 @@ MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { SourceLocation EllipsisLoc; TryConsumeToken(tok::ellipsis, EllipsisLoc); + if (TemplateTypeTy.isInvalid()) + return true; return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, - TemplateTypeTy, DS, IdLoc, + TemplateTypeTy.get(), DS, IdLoc, T.getOpenLocation(), ArgExprs, T.getCloseLocation(), EllipsisLoc); } + if (TemplateTypeTy.isInvalid()) + return true; + if (getLangOpts().CPlusPlus11) return Diag(Tok, diag::err_expected_either) << tok::l_paren << tok::l_brace; else diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index bcd5679cb43f2..fc07cfe5ad03f 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1455,7 +1455,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, break; case tok::annot_typename: if (isStartOfObjCClassMessageMissingOpenBracket()) { - ParsedType Type = getTypeAnnotation(Tok); + TypeResult Type = getTypeAnnotation(Tok); // Fake up a Declarator to use with ActOnTypeName. DeclSpec DS(AttrFactory); @@ -2102,8 +2102,14 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { OpKind, SS, TemplateKWLoc, Name, CurParsedObjCImpl ? CurParsedObjCImpl->Dcl : nullptr); - if (!LHS.isInvalid() && Tok.is(tok::less)) - checkPotentialAngleBracket(LHS); + if (!LHS.isInvalid()) { + if (Tok.is(tok::less)) + checkPotentialAngleBracket(LHS); + } else if (OrigLHS && Name.isValid()) { + // Preserve the LHS if the RHS is an invalid member. + LHS = Actions.CreateRecoveryExpr(OrigLHS->getBeginLoc(), + Name.getEndLoc(), {OrigLHS}); + } break; } case tok::plusplus: // postfix-expression: postfix-expression '++' @@ -2642,6 +2648,33 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { return ParsePostfixExpressionSuffix(Res.get()); } +bool Parser::tryParseOpenMPArrayShapingCastPart() { + assert(Tok.is(tok::l_square) && "Expected open bracket"); + bool ErrorFound = true; + TentativeParsingAction TPA(*this); + do { + if (Tok.isNot(tok::l_square)) + break; + // Consume '[' + ConsumeBracket(); + // Skip inner expression. + while (!SkipUntil(tok::r_square, tok::annot_pragma_openmp_end, + StopAtSemi | StopBeforeMatch)) + ; + if (Tok.isNot(tok::r_square)) + break; + // Consume ']' + ConsumeBracket(); + // Found ')' - done. + if (Tok.is(tok::r_paren)) { + ErrorFound = false; + break; + } + } while (Tok.isNot(tok::annot_pragma_openmp_end)); + TPA.Revert(); + return !ErrorFound; +} + /// ParseParenExpression - This parses the unit that starts with a '(' token, /// based on what is allowed by ExprType. The actual thing parsed is returned /// in ExprType. If stopIfCastExpr is true, it will only return the parsed type, @@ -2666,6 +2699,8 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { /// '(' '...' fold-operator cast-expression ')' /// '(' cast-expression fold-operator '...' /// fold-operator cast-expression ')' +/// [OPENMP] Array shaping operation +/// '(' '[' expression ']' { '[' expression ']' } cast-expression /// \endverbatim ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, @@ -2942,6 +2977,38 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), ArgExprs); } + } else if (getLangOpts().OpenMP >= 50 && OpenMPDirectiveParsing && + ExprType == CastExpr && Tok.is(tok::l_square) && + tryParseOpenMPArrayShapingCastPart()) { + bool ErrorFound = false; + SmallVector OMPDimensions; + SmallVector OMPBracketsRanges; + do { + BalancedDelimiterTracker TS(*this, tok::l_square); + TS.consumeOpen(); + ExprResult NumElements = + Actions.CorrectDelayedTyposInExpr(ParseExpression()); + if (!NumElements.isUsable()) { + ErrorFound = true; + while (!SkipUntil(tok::r_square, tok::r_paren, + StopAtSemi | StopBeforeMatch)) + ; + } + TS.consumeClose(); + OMPDimensions.push_back(NumElements.get()); + OMPBracketsRanges.push_back(TS.getRange()); + } while (Tok.isNot(tok::r_paren)); + // Match the ')'. + T.consumeClose(); + RParenLoc = T.getCloseLocation(); + Result = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + if (ErrorFound) { + Result = ExprError(); + } else if (!Result.isInvalid()) { + Result = Actions.ActOnOMPArrayShapingExpr( + Result.get(), OpenLoc, RParenLoc, OMPDimensions, OMPBracketsRanges); + } + return Result; } else { InMessageExpressionRAIIObject InMessage(*this, false); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index a0b97ea7514dc..c5e895d090a55 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -134,7 +134,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /// \param MayBePseudoDestructor When non-NULL, points to a flag that /// indicates whether this nested-name-specifier may be part of a /// pseudo-destructor name. In this case, the flag will be set false -/// if we don't actually end up parsing a destructor name. Moreorover, +/// if we don't actually end up parsing a destructor name. Moreover, /// if we do end up determining that we are parsing a destructor name, /// the last component of the nested-name-specifier is not parsed as /// part of the scope specifier. @@ -316,13 +316,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier( // Commit to parsing the template-id. TPA.Commit(); TemplateTy Template; - if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName( - getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, - EnteringContext, Template, /*AllowInjectedClassName*/ true)) { - if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, - TemplateName, false)) - return true; - } else + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateKWLoc, + TemplateName, false)) return true; continue; @@ -356,7 +354,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); - if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), + if (TemplateId->isInvalid() || + Actions.ActOnCXXNestedNameSpecifier(getCurScope(), SS, TemplateId->TemplateKWLoc, TemplateId->Template, @@ -512,7 +511,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier( if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && (IsTypename || isTemplateArgumentList(1) == TPResult::True)) { // If we had errors before, ObjectType can be dependent even without any - // templates, do not report missing template keyword in that case. + // templates. Do not report missing template keyword in that case. if (!ObjectHadErrors) { // We have something like t::getAs, where getAs is a // member of an unknown specialization. However, this will only @@ -527,16 +526,13 @@ bool Parser::ParseOptionalCXXScopeSpecifier( << FixItHint::CreateInsertion(Tok.getLocation(), "template "); } - if (TemplateNameKind TNK = Actions.ActOnDependentTemplateName( - getCurScope(), SS, Tok.getLocation(), TemplateName, ObjectType, - EnteringContext, Template, /*AllowInjectedClassName*/ true)) { - // Consume the identifier. - ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), - TemplateName, false)) - return true; - } - else + SourceLocation TemplateNameLoc = ConsumeToken(); + + TemplateNameKind TNK = Actions.ActOnTemplateName( + getCurScope(), SS, TemplateNameLoc, TemplateName, ObjectType, + EnteringContext, Template, /*AllowInjectedClassName*/ true); + if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), + TemplateName, false)) return true; continue; @@ -1738,8 +1734,11 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); CCLoc = ConsumeToken(); } else if (Tok.is(tok::annot_template_id)) { - FirstTypeName.setTemplateId( - (TemplateIdAnnotation *)Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + // FIXME: Carry on and build an AST representation for tooling. + if (TemplateId->isInvalid()) + return ExprError(); + FirstTypeName.setTemplateId(TemplateId); ConsumeAnnotationToken(); assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail"); CCLoc = ConsumeToken(); @@ -1774,6 +1773,12 @@ Parser::ParseCXXPseudoDestructor(Expr *Base, SourceLocation OpLoc, // If there is a '<', the second type name is a template-id. Parse // it as such. + // + // FIXME: This is not a context in which a '<' is assumed to start a template + // argument list. This affects examples such as + // void f(auto *p) { p->~X(); } + // ... but there's no ambiguity, and nowhere to write 'template' in such an + // example, so we accept it anyway. if (Tok.is(tok::less) && ParseUnqualifiedIdTemplateId( SS, ObjectType, Base && Base->containsErrors(), SourceLocation(), @@ -2142,12 +2147,8 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { // type-name case tok::annot_typename: { - if (getTypeAnnotation(Tok)) - DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, - getTypeAnnotation(Tok), Policy); - else - DS.SetTypeSpecError(); - + DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, + getTypeAnnotation(Tok), Policy); DS.SetRangeEnd(Tok.getAnnotationEndLoc()); ConsumeAnnotationToken(); @@ -2303,11 +2304,9 @@ bool Parser::ParseUnqualifiedIdTemplateId( if (AssumeTemplateId) { // We defer the injected-class-name checks until we've found whether // this template-id is used to form a nested-name-specifier or not. - TNK = Actions.ActOnDependentTemplateName( - getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, - Template, /*AllowInjectedClassName*/ true); - if (TNK == TNK_Non_template) - return true; + TNK = Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Id, + ObjectType, EnteringContext, Template, + /*AllowInjectedClassName*/ true); } else { bool MemberOfUnknownSpecialization; TNK = Actions.isTemplateName(getCurScope(), SS, @@ -2344,11 +2343,11 @@ bool Parser::ParseUnqualifiedIdTemplateId( << Name << FixItHint::CreateInsertion(Id.StartLocation, "template "); } - TNK = Actions.ActOnDependentTemplateName( + TNK = Actions.ActOnTemplateName( getCurScope(), SS, TemplateKWLoc, Id, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true); - if (TNK == TNK_Non_template) - return true; + } else if (TNK == TNK_Non_template) { + return false; } } break; @@ -2361,6 +2360,8 @@ bool Parser::ParseUnqualifiedIdTemplateId( TemplateName, ObjectType, EnteringContext, Template, MemberOfUnknownSpecialization); + if (TNK == TNK_Non_template) + return false; break; } @@ -2369,11 +2370,9 @@ bool Parser::ParseUnqualifiedIdTemplateId( bool MemberOfUnknownSpecialization; TemplateName.setIdentifier(Name, NameLoc); if (ObjectType) { - TNK = Actions.ActOnDependentTemplateName( + TNK = Actions.ActOnTemplateName( getCurScope(), SS, TemplateKWLoc, TemplateName, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true); - if (TNK == TNK_Non_template) - return true; } else { TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(), TemplateName, ObjectType, @@ -2383,7 +2382,7 @@ bool Parser::ParseUnqualifiedIdTemplateId( if (TNK == TNK_Non_template && !Id.DestructorName.get()) { Diag(NameLoc, diag::err_destructor_template_id) << Name << SS.getRange(); - return true; + // Carry on to parse the template arguments before bailing out. } } break; @@ -2393,9 +2392,6 @@ bool Parser::ParseUnqualifiedIdTemplateId( return false; } - if (TNK == TNK_Non_template) - return false; - // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; @@ -2403,6 +2399,10 @@ bool Parser::ParseUnqualifiedIdTemplateId( RAngleLoc)) return true; + // If this is a non-template, we already issued a diagnostic. + if (TNK == TNK_Non_template) + return true; + if (Id.getKind() == UnqualifiedIdKind::IK_Identifier || Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId || Id.getKind() == UnqualifiedIdKind::IK_LiteralOperatorId) { @@ -2420,7 +2420,7 @@ bool Parser::ParseUnqualifiedIdTemplateId( TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( TemplateKWLoc, Id.StartLocation, TemplateII, OpKind, Template, TNK, - LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); + LAngleLoc, RAngleLoc, TemplateArgs, /*ArgsInvalid*/false, TemplateIds); Id.setTemplateId(TemplateId); return false; @@ -2786,7 +2786,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), Id, IdLoc, EnteringContext, Result, TemplateSpecified); else if (TemplateSpecified && - Actions.ActOnDependentTemplateName( + Actions.ActOnTemplateName( getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true) == TNK_Non_template) @@ -2800,6 +2800,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + // FIXME: Consider passing invalid template-ids on to callers; they may + // be able to recover better than we can. + if (TemplateId->isInvalid()) { + ConsumeAnnotationToken(); + return true; + } + // If the template-name names the current class, then this is a constructor if (AllowConstructorName && TemplateId->Name && Actions.isCurrentClassName(*TemplateId->Name, getCurScope(), &SS)) { @@ -2865,7 +2872,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, TemplateKWLoc ? *TemplateKWLoc : SourceLocation(), nullptr, SourceLocation(), EnteringContext, Result, TemplateSpecified); else if (TemplateSpecified && - Actions.ActOnDependentTemplateName( + Actions.ActOnTemplateName( getCurScope(), SS, *TemplateKWLoc, Result, ObjectType, EnteringContext, Template, /*AllowInjectedClassName*/ true) == TNK_Non_template) @@ -3094,10 +3101,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { auto RunSignatureHelp = [&]() { ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); - assert(TypeRep && "invalid types should be handled before"); - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); + QualType PreferredType; + // ActOnTypeName might adjust DeclaratorInfo and return a null type even + // the passing DeclaratorInfo is valid, e.g. running SignatureHelp on + // `new decltype(invalid) (^)`. + if (TypeRep) + PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); CalledSignatureHelp = true; return PreferredType; }; @@ -3541,6 +3552,8 @@ ExprResult Parser::ParseRequiresExpression() { } else { TemplateId = takeTemplateIdAnnotation(Tok); ConsumeAnnotationToken(); + if (TemplateId->isInvalid()) + break; } if (auto *Req = Actions.ActOnTypeRequirement(TypenameKWLoc, SS, diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 1c61631513867..10252b08a8d16 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -523,10 +523,9 @@ ObjCTypeParamList *Parser::parseObjCTypeParamListOrProtocolRefs( SkipUntil(tok::greater, tok::at, StopBeforeMatch); if (Tok.is(tok::greater)) ConsumeToken(); - } else if (ParseGreaterThanInTemplateList(rAngleLoc, + } else if (ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, /*ConsumeLastToken=*/true, /*ObjCGenericList=*/true)) { - Diag(lAngleLoc, diag::note_matching) << "'<'"; SkipUntil({tok::greater, tok::greaterequal, tok::at, tok::minus, tok::minus, tok::plus, tok::colon, tok::l_paren, tok::l_brace, tok::comma, tok::semi }, @@ -1551,7 +1550,7 @@ ParseObjCProtocolReferences(SmallVectorImpl &Protocols, } // Consume the '>'. - if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken, + if (ParseGreaterThanInTemplateList(LAngleLoc, EndLoc, consumeLastToken, /*ObjCGenericList=*/false)) return true; @@ -1649,7 +1648,7 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( if (allSingleIdentifiers) { // Parse the closing '>'. SourceLocation rAngleLoc; - (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken, /*ObjCGenericList=*/true); // Let Sema figure out what we parsed. @@ -1755,7 +1754,7 @@ void Parser::parseObjCTypeArgsOrProtocolQualifiers( // Parse the closing '>'. SourceLocation rAngleLoc; - (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken, + (void)ParseGreaterThanInTemplateList(lAngleLoc, rAngleLoc, consumeLastToken, /*ObjCGenericList=*/true); if (invalid) { @@ -2979,7 +2978,7 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() { InMessageExpression) return false; - ParsedType Type; + TypeResult Type; if (Tok.is(tok::annot_typename)) Type = getTypeAnnotation(Tok); @@ -2989,7 +2988,8 @@ bool Parser::isStartOfObjCClassMessageMissingOpenBracket() { else return false; - if (!Type.get().isNull() && Type.get()->isObjCObjectOrInterfaceType()) { + // FIXME: Should not be querying properties of types from the parser. + if (Type.isUsable() && Type.get().get()->isObjCObjectOrInterfaceType()) { const Token &AfterNext = GetLookAheadToken(2); if (AfterNext.isOneOf(tok::colon, tok::r_square)) { if (Tok.is(tok::identifier)) diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 7ae9885abe2bd..4bec5f557ab8b 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -11,8 +11,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" @@ -48,6 +50,8 @@ enum OpenMPDirectiveKindEx { OMPD_target_teams_distribute_parallel, OMPD_mapper, OMPD_variant, + OMPD_begin, + OMPD_begin_declare, }; // Helper to unify the enum class OpenMPDirectiveKind with its extension @@ -101,6 +105,7 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) { .Case("update", OMPD_update) .Case("mapper", OMPD_mapper) .Case("variant", OMPD_variant) + .Case("begin", OMPD_begin) .Default(OMPD_unknown); } @@ -109,18 +114,21 @@ static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) { // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd // TODO: add other combined directives in topological order. static const OpenMPDirectiveKindExWrapper F[][3] = { + {OMPD_begin, OMPD_declare, OMPD_begin_declare}, + {OMPD_end, OMPD_declare, OMPD_end_declare}, {OMPD_cancellation, OMPD_point, OMPD_cancellation_point}, {OMPD_declare, OMPD_reduction, OMPD_declare_reduction}, {OMPD_declare, OMPD_mapper, OMPD_declare_mapper}, {OMPD_declare, OMPD_simd, OMPD_declare_simd}, {OMPD_declare, OMPD_target, OMPD_declare_target}, {OMPD_declare, OMPD_variant, OMPD_declare_variant}, + {OMPD_begin_declare, OMPD_variant, OMPD_begin_declare_variant}, + {OMPD_end_declare, OMPD_variant, OMPD_end_declare_variant}, {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel}, {OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for}, {OMPD_distribute_parallel_for, OMPD_simd, OMPD_distribute_parallel_for_simd}, {OMPD_distribute, OMPD_simd, OMPD_distribute_simd}, - {OMPD_end, OMPD_declare, OMPD_end_declare}, {OMPD_end_declare, OMPD_target, OMPD_end_declare_target}, {OMPD_target, OMPD_data, OMPD_target_data}, {OMPD_target, OMPD_enter, OMPD_target_enter}, @@ -748,7 +756,8 @@ static bool parseDeclareSimdClauses( getOpenMPClauseKind(ClauseName), *Vars, Data)) IsError = true; if (CKind == OMPC_aligned) { - Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr); + Alignments.append(Aligneds.size() - Alignments.size(), + Data.DepModOrTailExpr); } else if (CKind == OMPC_linear) { assert(0 <= Data.ExtraModifier && Data.ExtraModifier <= OMPC_LINEAR_unknown && @@ -759,7 +768,7 @@ static bool parseDeclareSimdClauses( Data.ExtraModifier = OMPC_LINEAR_val; LinModifiers.append(Linears.size() - LinModifiers.size(), Data.ExtraModifier); - Steps.append(Linears.size() - Steps.size(), Data.TailExpr); + Steps.append(Linears.size() - Steps.size(), Data.DepModOrTailExpr); } } else // TODO: add parsing of other clauses. @@ -796,13 +805,7 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen, Uniforms, Aligneds, Alignments, Linears, LinModifiers, Steps); - // Need to check for extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_declare_simd); - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); - } + skipUntilPragmaOpenMPEnd(OMPD_declare_simd); // Skip the last annot_pragma_openmp_end. SourceLocation EndLoc = ConsumeAnnotationToken(); if (IsError) @@ -863,7 +866,7 @@ static bool checkForDuplicates(Parser &P, StringRef Name, } // namespace void Parser::parseOMPTraitPropertyKind( - OMPTraitInfo::OMPTraitProperty &TIProperty, llvm::omp::TraitSet Set, + OMPTraitProperty &TIProperty, llvm::omp::TraitSet Set, llvm::omp::TraitSelector Selector, llvm::StringMap &Seen) { TIProperty.Kind = TraitProperty::invalid; @@ -932,14 +935,14 @@ void Parser::parseOMPTraitPropertyKind( << CONTEXT_TRAIT_LVL << listOpenMPContextTraitProperties(Set, Selector); } -void Parser::parseOMPContextProperty(OMPTraitInfo::OMPTraitSelector &TISelector, +void Parser::parseOMPContextProperty(OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &Seen) { assert(TISelector.Kind != TraitSelector::user_condition && "User conditions are special properties not handled here!"); SourceLocation PropertyLoc = Tok.getLocation(); - OMPTraitInfo::OMPTraitProperty TIProperty; + OMPTraitProperty TIProperty; parseOMPTraitPropertyKind(TIProperty, Set, TISelector.Kind, Seen); // If we have an invalid property here we already issued a warning. @@ -973,7 +976,7 @@ void Parser::parseOMPContextProperty(OMPTraitInfo::OMPTraitSelector &TISelector, } void Parser::parseOMPTraitSelectorKind( - OMPTraitInfo::OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, + OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &Seen) { TISelector.Kind = TraitSelector::invalid; @@ -1052,7 +1055,7 @@ static ExprResult parseContextScore(Parser &P) { /// /// ['('[] [, ]* ')'] void Parser::parseOMPContextSelector( - OMPTraitInfo::OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, + OMPTraitSelector &TISelector, llvm::omp::TraitSet Set, llvm::StringMap &SeenSelectors) { unsigned short OuterPC = ParenCount; @@ -1130,13 +1133,19 @@ void Parser::parseOMPContextSelector( // Parse '('. (void)BDT.consumeOpen(); + SourceLocation ScoreLoc = Tok.getLocation(); ExprResult Score = parseContextScore(*this); - if (!AllowsTraitScore && Score.isUsable()) { - Diag(Score.get()->getBeginLoc(), - diag::warn_omp_ctx_incompatible_score_for_property) - << getOpenMPContextTraitSelectorName(TISelector.Kind) - << getOpenMPContextTraitSetName(Set) << Score.get(); + if (!AllowsTraitScore && !Score.isUnset()) { + if (Score.isUsable()) { + Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property) + << getOpenMPContextTraitSelectorName(TISelector.Kind) + << getOpenMPContextTraitSetName(Set) << Score.get(); + } else { + Diag(ScoreLoc, diag::warn_omp_ctx_incompatible_score_for_property) + << getOpenMPContextTraitSelectorName(TISelector.Kind) + << getOpenMPContextTraitSetName(Set) << ""; + } Score = ExprResult(); } @@ -1152,7 +1161,7 @@ void Parser::parseOMPContextSelector( BDT.consumeClose(); } -void Parser::parseOMPTraitSetKind(OMPTraitInfo::OMPTraitSet &TISet, +void Parser::parseOMPTraitSetKind(OMPTraitSet &TISet, llvm::StringMap &Seen) { TISet.Kind = TraitSet::invalid; @@ -1216,7 +1225,7 @@ void Parser::parseOMPTraitSetKind(OMPTraitInfo::OMPTraitSet &TISet, /// /// '=' '{' [, ]* '}' void Parser::parseOMPContextSelectorSet( - OMPTraitInfo::OMPTraitSet &TISet, + OMPTraitSet &TISet, llvm::StringMap &SeenSets) { auto OuterBC = BraceCount; @@ -1271,7 +1280,7 @@ void Parser::parseOMPContextSelectorSet( llvm::StringMap SeenSelectors; do { - OMPTraitInfo::OMPTraitSelector TISelector; + OMPTraitSelector TISelector; parseOMPContextSelector(TISelector, TISet.Kind, SeenSelectors); if (TISelector.Kind != TraitSelector::invalid && !TISelector.Properties.empty()) @@ -1293,10 +1302,10 @@ void Parser::parseOMPContextSelectorSet( /// Parse OpenMP context selectors: /// /// [, ]* -bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI) { +bool Parser::parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo& TI) { llvm::StringMap SeenSets; do { - OMPTraitInfo::OMPTraitSet TISet; + OMPTraitSet TISet; parseOMPContextSelectorSet(TISet, SeenSets); if (TISet.Kind != TraitSet::invalid && !TISet.Selectors.empty()) TI.Sets.push_back(TISet); @@ -1340,6 +1349,29 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, return; } + OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); + if (parseOMPDeclareVariantMatchClause(Loc, TI)) + return; + + Optional> DeclVarData = + Actions.checkOpenMPDeclareVariantFunction( + Ptr, AssociatedFunction.get(), TI, + SourceRange(Loc, Tok.getLocation())); + + // Skip last tokens. + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + if (DeclVarData && !TI.Sets.empty()) + Actions.ActOnOpenMPDeclareVariantDirective( + DeclVarData->first, DeclVarData->second, TI, + SourceRange(Loc, Tok.getLocation())); + + // Skip the last annot_pragma_openmp_end. + (void)ConsumeAnnotationToken(); +} + +bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, + OMPTraitInfo &TI) { // Parse 'match'. OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown @@ -1351,7 +1383,7 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, ; // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); - return; + return true; } (void)ConsumeToken(); // Parse '('. @@ -1362,31 +1394,15 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, ; // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); - return; + return true; } // Parse inner context selectors. - OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); parseOMPContextSelectors(Loc, TI); // Parse ')' (void)T.consumeClose(); - - Optional> DeclVarData = - Actions.checkOpenMPDeclareVariantFunction( - Ptr, AssociatedFunction.get(), TI, - SourceRange(Loc, Tok.getLocation())); - - // Skip last tokens. - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); - if (DeclVarData.hasValue() && !TI.Sets.empty()) - Actions.ActOnOpenMPDeclareVariantDirective( - DeclVarData.getValue().first, DeclVarData.getValue().second, TI, - SourceRange(Loc, Tok.getLocation())); - - // Skip the last annot_pragma_openmp_end. - (void)ConsumeAnnotationToken(); + return false; } /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. @@ -1524,21 +1540,48 @@ Parser::DeclGroupPtrTy Parser::ParseOMPDeclareTargetClauses() { return Actions.BuildDeclaratorGroup(Decls); } -void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, - SourceLocation DTLoc) { - if (DKind != OMPD_end_declare_target) { - Diag(Tok, diag::err_expected_end_declare_target); - Diag(DTLoc, diag::note_matching) << "'#pragma omp declare target'"; +void Parser::skipUntilPragmaOpenMPEnd(OpenMPDirectiveKind DKind) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.is(tok::annot_pragma_openmp_end)) + return; + + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(DKind); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); +} + +void Parser::parseOMPEndDirective(OpenMPDirectiveKind BeginKind, + OpenMPDirectiveKind ExpectedKind, + OpenMPDirectiveKind FoundKind, + SourceLocation BeginLoc, + SourceLocation FoundLoc, + bool SkipUntilOpenMPEnd) { + int DiagSelection = ExpectedKind == OMPD_end_declare_target ? 0 : 1; + + if (FoundKind == ExpectedKind) { + ConsumeAnyToken(); + skipUntilPragmaOpenMPEnd(ExpectedKind); return; } - ConsumeAnyToken(); - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_end_declare_target); + + Diag(FoundLoc, diag::err_expected_end_declare_target_or_variant) + << DiagSelection; + Diag(BeginLoc, diag::note_matching) + << ("'#pragma omp " + getOpenMPDirectiveName(BeginKind) + "'").str(); + if (SkipUntilOpenMPEnd) SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); - } +} + +void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, + SourceLocation DKLoc) { + parseOMPEndDirective(OMPD_declare_target, OMPD_end_declare_target, DKind, + DKLoc, Tok.getLocation(), + /* SkipUntilOpenMPEnd */ false); // Skip the last annot_pragma_openmp_end. - ConsumeAnyToken(); + if (Tok.is(tok::annot_pragma_openmp_end)) + ConsumeAnnotationToken(); } /// Parsing of declarative OpenMP directives. @@ -1616,13 +1659,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( DeclDirectiveListParserHelper Helper(this, DKind); if (!ParseOpenMPSimpleVarList(DKind, Helper, /*AllowScopeSpecifier=*/true)) { - // The last seen token is annot_pragma_openmp_end - need to check for - // extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); - } + skipUntilPragmaOpenMPEnd(DKind); // Skip the last annot_pragma_openmp_end. ConsumeAnnotationToken(); return Actions.ActOnOpenMPThreadprivateDirective(Loc, @@ -1661,13 +1698,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( ConsumeToken(); Actions.EndOpenMPClause(); } - // The last seen token is annot_pragma_openmp_end - need to check for - // extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); - } + skipUntilPragmaOpenMPEnd(DKind); } // Skip the last annot_pragma_openmp_end. ConsumeAnnotationToken(); @@ -1720,14 +1751,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_declare_reduction: ConsumeToken(); if (DeclGroupPtrTy Res = ParseOpenMPDeclareReductionDirective(AS)) { - // The last seen token is annot_pragma_openmp_end - need to check for - // extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_declare_reduction); - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); - } + skipUntilPragmaOpenMPEnd(OMPD_declare_reduction); // Skip the last annot_pragma_openmp_end. ConsumeAnnotationToken(); return Res; @@ -1742,6 +1766,61 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( } break; } + case OMPD_begin_declare_variant: { + // The syntax is: + // { #pragma omp begin declare variant clause } + // + // { #pragma omp end declare variant } + // + ConsumeToken(); + OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); + if (parseOMPDeclareVariantMatchClause(Loc, TI)) + break; + + // Skip last tokens. + skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant); + + VariantMatchInfo VMI; + ASTContext &ASTCtx = Actions.getASTContext(); + TI.getAsVariantMatchInfo(ASTCtx, VMI, /* DeviceSetOnly */ true); + OMPContext OMPCtx(ASTCtx.getLangOpts().OpenMPIsDevice, + ASTCtx.getTargetInfo().getTriple()); + + if (isVariantApplicableInContext(VMI, OMPCtx)) { + Actions.ActOnOpenMPBeginDeclareVariant(Loc, TI); + break; + } + + // Elide all the code till the matching end declare variant was found. + unsigned Nesting = 1; + SourceLocation DKLoc; + OpenMPDirectiveKind DK = OMPD_unknown; + do { + DKLoc = Tok.getLocation(); + DK = parseOpenMPDirectiveKind(*this); + if (DK == OMPD_end_declare_variant) + --Nesting; + else if (DK == OMPD_begin_declare_variant) + ++Nesting; + if (!Nesting || isEofOrEom()) + break; + ConsumeAnyToken(); + } while (true); + + parseOMPEndDirective(OMPD_begin_declare_variant, OMPD_end_declare_variant, + DK, Loc, DKLoc, /* SkipUntilOpenMPEnd */ true); + if (isEofOrEom()) + return nullptr; + break; + } + case OMPD_end_declare_variant: { + if (Actions.isInOpenMPDeclareVariantScope()) + Actions.ActOnOpenMPEndDeclareVariant(); + else + Diag(Loc, diag::err_expected_begin_declare_variant); + ConsumeToken(); + break; + } case OMPD_declare_variant: case OMPD_declare_simd: { // The syntax is: @@ -1970,13 +2049,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { DeclDirectiveListParserHelper Helper(this, DKind); if (!ParseOpenMPSimpleVarList(DKind, Helper, /*AllowScopeSpecifier=*/false)) { - // The last seen token is annot_pragma_openmp_end - need to check for - // extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); - } + skipUntilPragmaOpenMPEnd(DKind); DeclGroupPtrTy Res = Actions.ActOnOpenMPThreadprivateDirective( Loc, Helper.getIdentifiers()); Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); @@ -2021,13 +2094,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { ConsumeToken(); Actions.EndOpenMPClause(); } - // The last seen token is annot_pragma_openmp_end - need to check for - // extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); - } + skipUntilPragmaOpenMPEnd(DKind); } DeclGroupPtrTy Res = Actions.ActOnOpenMPAllocateDirective( Loc, Helper.getIdentifiers(), Clauses); @@ -2040,14 +2107,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { ConsumeToken(); if (DeclGroupPtrTy Res = ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) { - // The last seen token is annot_pragma_openmp_end - need to check for - // extra tokens. - if (Tok.isNot(tok::annot_pragma_openmp_end)) { - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(OMPD_declare_reduction); - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); - } + skipUntilPragmaOpenMPEnd(OMPD_declare_reduction); ConsumeAnyToken(); Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); } else { @@ -2251,6 +2311,8 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_requires: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_variant: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); @@ -2521,9 +2583,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, break; case OMPC_device_type: case OMPC_unknown: - Diag(Tok, diag::warn_omp_extra_tokens_at_eol) - << getOpenMPDirectiveName(DKind); - SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + skipUntilPragmaOpenMPEnd(DKind); break; case OMPC_threadprivate: case OMPC_uniform: @@ -2996,6 +3056,114 @@ static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) { P.ConsumeToken(); } +/// 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."); + SourceLocation IteratorKwLoc = ConsumeToken(); + + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, "iterator")) + return ExprError(); + + SourceLocation LLoc = T.getOpenLocation(); + SmallVector Data; + while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { + // Check if the type parsing is required. + ParsedType IteratorType; + if (Tok.isNot(tok::identifier) || NextToken().isNot(tok::equal)) { + // identifier '=' is not found - parse type. + TypeResult TR = ParseTypeName(); + if (TR.isInvalid()) { + T.skipToEnd(); + return ExprError(); + } + IteratorType = TR.get(); + } + + // Parse identifier. + IdentifierInfo *II = nullptr; + SourceLocation IdLoc; + if (Tok.is(tok::identifier)) { + II = Tok.getIdentifierInfo(); + IdLoc = ConsumeToken(); + } else { + Diag(Tok, diag::err_expected_unqualified_id) << 0; + } + + // Parse '='. + SourceLocation AssignLoc; + if (Tok.is(tok::equal)) + AssignLoc = ConsumeToken(); + else + Diag(Tok, diag::err_omp_expected_equal_in_iterator); + + // Parse range-specification - ':' [ ':' ] + ColonProtectionRAIIObject ColonRAII(*this); + // Parse + SourceLocation Loc = Tok.getLocation(); + ExprResult LHS = ParseCastExpression(AnyCastExpr); + ExprResult Begin = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + Begin = Actions.ActOnFinishFullExpr(Begin.get(), Loc, + /*DiscardedValue=*/false); + // Parse ':'. + SourceLocation ColonLoc; + if (Tok.is(tok::colon)) + ColonLoc = ConsumeToken(); + + // Parse + Loc = Tok.getLocation(); + LHS = ParseCastExpression(AnyCastExpr); + ExprResult End = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + End = Actions.ActOnFinishFullExpr(End.get(), Loc, + /*DiscardedValue=*/false); + + SourceLocation SecColonLoc; + ExprResult Step; + // Parse optional step. + if (Tok.is(tok::colon)) { + // Parse ':' + SecColonLoc = ConsumeToken(); + // Parse + Loc = Tok.getLocation(); + LHS = ParseCastExpression(AnyCastExpr); + Step = Actions.CorrectDelayedTyposInExpr( + ParseRHSOfBinaryExpression(LHS, prec::Conditional)); + Step = Actions.ActOnFinishFullExpr(Step.get(), Loc, + /*DiscardedValue=*/false); + } + + // Parse ',' or ')' + if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren)) + Diag(Tok, diag::err_omp_expected_punc_after_iterator); + if (Tok.is(tok::comma)) + ConsumeToken(); + + Sema::OMPIteratorData &D = Data.emplace_back(); + D.DeclIdent = II; + D.DeclIdentLoc = IdLoc; + D.Type = IteratorType; + D.AssignLoc = AssignLoc; + D.ColonLoc = ColonLoc; + D.SecColonLoc = SecColonLoc; + D.Range.Begin = Begin.get(); + D.Range.End = End.get(); + D.Range.Step = Step.get(); + } + + // Parse ')'. + SourceLocation RLoc = Tok.getLocation(); + if (!T.consumeClose()) + RLoc = T.getCloseLocation(); + + return Actions.ActOnOMPIteratorExpr(getCurScope(), IteratorKwLoc, LLoc, RLoc, + Data); +} + /// Parses clauses with list. bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, OpenMPClauseKind Kind, @@ -3011,6 +3179,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, getOpenMPClauseName(Kind))) return true; + bool DependWithIterator = false; bool NeedRParenForLinear = false; BalancedDelimiterTracker LinearT(*this, tok::l_paren, tok::annot_pragma_openmp_end); @@ -3048,6 +3217,22 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ReductionOrMapperId = Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); } else if (Kind == OMPC_depend) { + if (getLangOpts().OpenMP >= 50) { + if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") { + // Handle optional dependence modifier. + // iterator(iterators-definition) + // where iterators-definition is iterator-specifier [, + // iterators-definition ] + // where iterator-specifier is [ iterator-type ] identifier = + // range-specification + DependWithIterator = true; + EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope); + ExprResult IteratorRes = ParseOpenMPIteratorsExpr(); + Data.DepModOrTailExpr = IteratorRes.get(); + // Parse ',' + ExpectAndConsume(tok::comma); + } + } // Handle dependency type for depend clause. ColonProtectionRAIIObject ColonRAII(*this); Data.ExtraModifier = getOpenMPSimpleClauseType( @@ -3169,7 +3354,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /*DiscardedValue=*/false); if (Tail.isUsable()) { if (Tok.is(tok::colon)) { - Data.TailExpr = Tail.get(); + Data.DepModOrTailExpr = Tail.get(); Data.ColonLoc = ConsumeToken(); TPA.Commit(); } else { @@ -3195,6 +3380,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { + ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope); ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail); // Parse variable ExprResult VarExpr = @@ -3231,7 +3417,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Tail = Actions.ActOnFinishFullExpr(Tail.get(), ELoc, /*DiscardedValue*/ false); if (Tail.isUsable()) - Data.TailExpr = Tail.get(); + Data.DepModOrTailExpr = Tail.get(); else SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -3241,8 +3427,11 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.RLoc = Tok.getLocation(); if (!T.consumeClose()) Data.RLoc = T.getCloseLocation(); + // Exit from scope when the iterator is used in depend clause. + if (DependWithIterator) + ExitScope(); return (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || - (MustHaveTail && !Data.TailExpr) || InvalidReductionId || + (MustHaveTail && !Data.DepModOrTailExpr) || InvalidReductionId || IsInvalidMapperModifier; } @@ -3314,7 +3503,7 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, return nullptr; OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc); return Actions.ActOnOpenMPVarListClause( - Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc, + Kind, Vars, Data.DepModOrTailExpr, Locs, Data.ColonLoc, Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, Data.IsMapTypeImplicit, Data.ExtraModifierLoc); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 802fe35d4f62a..5025ea5c85feb 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -1031,7 +1031,8 @@ void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, /// or argument list. /// /// \returns true, if current token does not start with '>', false otherwise. -bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, +bool Parser::ParseGreaterThanInTemplateList(SourceLocation LAngleLoc, + SourceLocation &RAngleLoc, bool ConsumeLastToken, bool ObjCGenericList) { // What will be left once we've consumed the '>'. @@ -1041,7 +1042,8 @@ bool Parser::ParseGreaterThanInTemplateList(SourceLocation &RAngleLoc, switch (Tok.getKind()) { default: - Diag(Tok.getLocation(), diag::err_expected) << tok::greater; + Diag(getEndOfPreviousToken(), diag::err_expected) << tok::greater; + Diag(LAngleLoc, diag::note_matching) << tok::less; return true; case tok::greater: @@ -1220,16 +1222,17 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, if (Invalid) { // Try to find the closing '>'. - if (ConsumeLastToken) - SkipUntil(tok::greater, StopAtSemi); + if (getLangOpts().CPlusPlus11) + SkipUntil(tok::greater, tok::greatergreater, + tok::greatergreatergreater, StopAtSemi | StopBeforeMatch); else SkipUntil(tok::greater, StopAtSemi | StopBeforeMatch); - return true; } } - return ParseGreaterThanInTemplateList(RAngleLoc, ConsumeLastToken, - /*ObjCGenericList=*/false); + return ParseGreaterThanInTemplateList(LAngleLoc, RAngleLoc, ConsumeLastToken, + /*ObjCGenericList=*/false) || + Invalid; } /// Replace the tokens that form a simple-template-id with an @@ -1280,12 +1283,13 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, bool AllowTypeAnnotation, bool TypeConstraint) { assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); - assert(Template && (Tok.is(tok::less) || TypeConstraint) && + assert((Tok.is(tok::less) || TypeConstraint) && "Parser isn't at the beginning of a template-id"); assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be " "a type annotation"); assert((!TypeConstraint || TNK == TNK_Concept_template) && "type-constraint " "must accompany a concept name"); + assert((Template || TNK == TNK_Non_template) && "missing template name"); // Consume the template-name. SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); @@ -1293,40 +1297,31 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; + bool ArgsInvalid = false; if (!TypeConstraint || Tok.is(tok::less)) { - bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, - TemplateArgs, - RAngleLoc); - - if (Invalid) { - // If we failed to parse the template ID but skipped ahead to a >, we're not - // going to be able to form a token annotation. Eat the '>' if present. - TryConsumeToken(tok::greater); - // FIXME: Annotate the token stream so we don't produce the same errors - // again if we're doing this annotation as part of a tentative parse. + ArgsInvalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, + TemplateArgs, RAngleLoc); + // If we couldn't recover from invalid arguments, don't form an annotation + // token -- we don't know how much to annotate. + // FIXME: This can lead to duplicate diagnostics if we retry parsing this + // template-id in another context. Try to annotate anyway? + if (RAngleLoc.isInvalid()) return true; - } } ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs); // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { - TypeResult Type = Actions.ActOnTemplateIdType( - getCurScope(), SS, TemplateKWLoc, Template, TemplateName.Identifier, - TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); - if (Type.isInvalid()) { - // If we failed to parse the template ID but skipped ahead to a >, we're - // not going to be able to form a token annotation. Eat the '>' if - // present. - TryConsumeToken(tok::greater); - // FIXME: Annotate the token stream so we don't produce the same errors - // again if we're doing this annotation as part of a tentative parse. - return true; - } + TypeResult Type = ArgsInvalid + ? TypeError() + : Actions.ActOnTemplateIdType( + getCurScope(), SS, TemplateKWLoc, Template, + TemplateName.Identifier, TemplateNameLoc, + LAngleLoc, TemplateArgsPtr, RAngleLoc); Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Type.get()); + setTypeAnnotation(Tok, Type); if (SS.isNotEmpty()) Tok.setLocation(SS.getBeginLoc()); else if (TemplateKWLoc.isValid()) @@ -1350,7 +1345,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create( TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK, - LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds); + LAngleLoc, RAngleLoc, TemplateArgs, ArgsInvalid, TemplateIds); Tok.setAnnotationValue(TemplateId); if (TemplateKWLoc.isValid()) @@ -1386,29 +1381,24 @@ void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS, assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - assert((TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name || - TemplateId->Kind == TNK_Undeclared_template) && + assert(TemplateId->mightBeType() && "Only works for type and dependent templates"); ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); - TypeResult Type - = Actions.ActOnTemplateIdType(getCurScope(), - SS, - TemplateId->TemplateKWLoc, - TemplateId->Template, - TemplateId->Name, - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc, - /*IsCtorOrDtorName*/false, - IsClassName); + TypeResult Type = + TemplateId->isInvalid() + ? TypeError() + : Actions.ActOnTemplateIdType( + getCurScope(), SS, TemplateId->TemplateKWLoc, + TemplateId->Template, TemplateId->Name, + TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, + TemplateArgsPtr, TemplateId->RAngleLoc, + /*IsCtorOrDtorName*/ false, IsClassName); // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Type.isInvalid() ? nullptr : Type.get()); + setTypeAnnotation(Tok, Type); if (SS.isNotEmpty()) // it was a C++ qualified type name. Tok.setLocation(SS.getBeginLoc()); // End location stays the same @@ -1420,7 +1410,9 @@ void Parser::AnnotateTemplateIdTokenAsType(CXXScopeSpec &SS, /// Determine whether the given token can end a template argument. static bool isEndOfTemplateArgument(Token Tok) { - return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater); + // FIXME: Handle '>>>'. + return Tok.isOneOf(tok::comma, tok::greater, tok::greatergreater, + tok::greatergreatergreater); } /// Parse a C++ template template argument. @@ -1460,15 +1452,14 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { TryConsumeToken(tok::ellipsis, EllipsisLoc); - // If the next token signals the end of a template argument, - // then we have a dependent template name that could be a template - // template argument. + // If the next token signals the end of a template argument, then we have + // a (possibly-dependent) template name that could be a template template + // argument. TemplateTy Template; if (isEndOfTemplateArgument(Tok) && - Actions.ActOnDependentTemplateName( - getCurScope(), SS, TemplateKWLoc, Name, - /*ObjectType=*/nullptr, - /*EnteringContext=*/false, Template)) + Actions.ActOnTemplateName(getCurScope(), SS, TemplateKWLoc, Name, + /*ObjectType=*/nullptr, + /*EnteringContext=*/false, Template)) Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } } else if (Tok.is(tok::identifier)) { @@ -1572,10 +1563,8 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc); - if (Arg.isInvalid()) { - SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch); + if (Arg.isInvalid()) return true; - } // Save this template argument. TemplateArgs.push_back(Arg); @@ -1755,7 +1744,7 @@ bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) { TPA.Commit(); SourceLocation Greater; - ParseGreaterThanInTemplateList(Greater, true, false); + ParseGreaterThanInTemplateList(Less, Greater, true, false); Actions.diagnoseExprIntendedAsTemplateName(getCurScope(), LHS, Less, Greater); return true; @@ -1784,7 +1773,7 @@ void Parser::checkPotentialAngleBracket(ExprResult &PotentialTemplateName) { NextToken().isOneOf(tok::greatergreater, tok::greatergreatergreater))) { SourceLocation Less = ConsumeToken(); SourceLocation Greater; - ParseGreaterThanInTemplateList(Greater, true, false); + ParseGreaterThanInTemplateList(Less, Greater, true, false); Actions.diagnoseExprIntendedAsTemplateName( getCurScope(), PotentialTemplateName, Less, Greater); // FIXME: Perform error recovery. diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index bca7d021da0a2..529e3f3210544 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -984,10 +984,16 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, NextToken().is(tok::kw_operator)))) && mayHaveIdentifier) { // declarator-id - if (Tok.is(tok::annot_cxxscope)) + if (Tok.is(tok::annot_cxxscope)) { + CXXScopeSpec SS; + Actions.RestoreNestedNameSpecifierAnnotation( + Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); + if (SS.isInvalid()) + return TPResult::Error; ConsumeAnnotationToken(); - else if (Tok.is(tok::identifier)) + } else if (Tok.is(tok::identifier)) { TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo()); + } if (Tok.is(tok::kw_operator)) { if (TryParseOperatorId() == TPResult::Error) return TPResult::Error; @@ -1539,7 +1545,9 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); // If lookup for the template-name found nothing, don't assume we have a // definitive disambiguation result yet. - if (TemplateId->Kind == TNK_Undeclared_template && InvalidAsDeclSpec) { + if ((TemplateId->hasInvalidName() || + TemplateId->Kind == TNK_Undeclared_template) && + InvalidAsDeclSpec) { // 'template-id(' can be a valid expression but not a valid decl spec if // the template-name is not declared, but we don't consider this to be a // definitive disambiguation. In any other context, it's an error either @@ -1547,6 +1555,8 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, *InvalidAsDeclSpec = NextToken().is(tok::l_paren); return TPResult::Ambiguous; } + if (TemplateId->hasInvalidName()) + return TPResult::Error; if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/0)) return TPResult::True; if (TemplateId->Kind != TNK_Type_template) @@ -1566,6 +1576,13 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, NextToken().is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(NextToken()); + if (TemplateId->hasInvalidName()) { + if (InvalidAsDeclSpec) { + *InvalidAsDeclSpec = NextToken().is(tok::l_paren); + return TPResult::Ambiguous; + } + return TPResult::Error; + } if (IsPlaceholderSpecifier(TemplateId, /*Lookahead=*/1)) return TPResult::True; } @@ -2012,17 +2029,14 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, // (a) the previous parameter did, and // (b) this must be the first declaration of the function, so we can't // inherit any default arguments from elsewhere. - // If we see an ')', then we've reached the end of a - // parameter-declaration-clause, and the last param is missing its default - // argument. + // FIXME: If we reach a ')' without consuming any '>'s, then this must + // also be a function parameter (that's missing its default argument). if (VersusTemplateArgument) - return Tok.isOneOf(tok::equal, tok::r_paren) ? TPResult::True - : TPResult::False; + return Tok.is(tok::equal) ? TPResult::True : TPResult::False; if (Tok.is(tok::equal)) { // '=' assignment-expression // Parse through assignment-expression. - // FIXME: assignment-expression may contain an unparenthesized comma. if (!SkipUntil(tok::comma, tok::r_paren, StopAtSemi | StopBeforeMatch)) return TPResult::Error; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 0a63ac2d5e1bc..e9dbd50c3ac10 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1878,9 +1878,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { Tok.getLocation()); } else if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); - if (TemplateId->Kind != TNK_Type_template && - TemplateId->Kind != TNK_Dependent_template_name && - TemplateId->Kind != TNK_Undeclared_template) { + if (!TemplateId->mightBeType()) { Diag(Tok, diag::err_typename_refers_to_non_type_template) << Tok.getAnnotationRange(); return true; @@ -1889,14 +1887,13 @@ bool Parser::TryAnnotateTypeOrScopeToken() { ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); - Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, - TemplateId->TemplateKWLoc, - TemplateId->Template, - TemplateId->Name, - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc); + Ty = TemplateId->isInvalid() + ? TypeError() + : Actions.ActOnTypenameType( + getCurScope(), TypenameLoc, SS, TemplateId->TemplateKWLoc, + TemplateId->Template, TemplateId->Name, + TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, + TemplateArgsPtr, TemplateId->RAngleLoc); } else { Diag(Tok, diag::err_expected_type_name_after_typename) << SS.getRange(); @@ -1905,7 +1902,7 @@ bool Parser::TryAnnotateTypeOrScopeToken() { SourceLocation EndLoc = Tok.getLastLoc(); Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Ty.isInvalid() ? nullptr : Ty.get()); + setTypeAnnotation(Tok, Ty); Tok.setAnnotationEndLoc(EndLoc); Tok.setLocation(TypenameLoc); PP.AnnotateCachedTokens(Tok); diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index b88ff9dd64cde..2402d896faac2 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -570,29 +570,10 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults( if (const char *BriefComment = CCS->getBriefComment()) OS << " : " << BriefComment; } - for (const FixItHint &FixIt : Results[I].FixIts) { - const SourceLocation BLoc = FixIt.RemoveRange.getBegin(); - const SourceLocation ELoc = FixIt.RemoveRange.getEnd(); - - SourceManager &SM = SemaRef.SourceMgr; - std::pair BInfo = SM.getDecomposedLoc(BLoc); - std::pair EInfo = SM.getDecomposedLoc(ELoc); - // Adjust for token ranges. - if (FixIt.RemoveRange.isTokenRange()) - EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts); - - OS << " (requires fix-it:" - << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << SM.getColumnNumber(EInfo.first, EInfo.second) << "}" - << " to \"" << FixIt.CodeToInsert << "\")"; - } - OS << '\n'; break; case CodeCompletionResult::RK_Keyword: - OS << Results[I].Keyword << '\n'; + OS << Results[I].Keyword; break; case CodeCompletionResult::RK_Macro: @@ -602,13 +583,31 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults( includeBriefComments())) { OS << " : " << CCS->getAsString(); } - OS << '\n'; break; case CodeCompletionResult::RK_Pattern: - OS << "Pattern : " << Results[I].Pattern->getAsString() << '\n'; + OS << "Pattern : " << Results[I].Pattern->getAsString(); break; } + for (const FixItHint &FixIt : Results[I].FixIts) { + const SourceLocation BLoc = FixIt.RemoveRange.getBegin(); + const SourceLocation ELoc = FixIt.RemoveRange.getEnd(); + + SourceManager &SM = SemaRef.SourceMgr; + std::pair BInfo = SM.getDecomposedLoc(BLoc); + std::pair EInfo = SM.getDecomposedLoc(ELoc); + // Adjust for token ranges. + if (FixIt.RemoveRange.isTokenRange()) + EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts); + + OS << " (requires fix-it:" + << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << SM.getColumnNumber(EInfo.first, EInfo.second) << "}" + << " to \"" << FixIt.CodeToInsert << "\")"; + } + OS << '\n'; } } diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 2da300a62dc3c..ae4a78a4556de 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -30,6 +30,9 @@ using namespace clang; void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { assert(TemplateId && "NULL template-id annotation?"); + assert(!TemplateId->isInvalid() && + "should not convert invalid template-ids to unqualified-ids"); + Kind = UnqualifiedIdKind::IK_TemplateId; this->TemplateId = TemplateId; StartLocation = TemplateId->TemplateNameLoc; @@ -38,6 +41,9 @@ void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { assert(TemplateId && "NULL template-id annotation?"); + assert(!TemplateId->isInvalid() && + "should not convert invalid template-ids to unqualified-ids"); + Kind = UnqualifiedIdKind::IK_ConstructorTemplateId; this->TemplateId = TemplateId; StartLocation = TemplateId->TemplateNameLoc; diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index 651ca8aefc3cc..f3397f69824b9 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -1275,15 +1275,6 @@ def : Builtin<"get_default_queue", [Queue]>; // TODO: ndrange functions -// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions -let MinVersion = CL20 in { - let Extension = FuncExtKhrSubgroups in { - def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>; - def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>; - def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>; - } -} - //-------------------------------------------------------------------- // End of the builtin functions defined in the OpenCL C specification. // Builtin functions defined in the OpenCL C Extension are below. @@ -1458,6 +1449,41 @@ let Extension = FuncExtKhrGlMsaaSharing in { } } +//-------------------------------------------------------------------- +// OpenCL Extension v2.0 s28 - Subgroups +// --- Table 28.2.1 --- +let Extension = FuncExtKhrSubgroups in { + foreach name = ["get_sub_group_size", "get_max_sub_group_size", + "get_num_sub_groups", "get_sub_group_id", + "get_sub_group_local_id"] in { + def : Builtin; + } + let MinVersion = CL20 in { + foreach name = ["get_enqueued_num_sub_groups"] in { + def : Builtin; + } + } +} + +// --- Table 28.2.2 --- +// TODO: sub_group_barrier + +// --- Table 28.2.4 --- +let Extension = FuncExtKhrSubgroups in { + foreach name = ["sub_group_all", "sub_group_any"] in { + def : Builtin; + } + foreach name = ["sub_group_broadcast"] in { + def : Builtin; + } + foreach name = ["sub_group_reduce_", "sub_group_scan_exclusive_", + "sub_group_scan_inclusive_"] in { + foreach op = ["add", "min", "max"] in { + def : Builtin; + } + } +} + //-------------------------------------------------------------------- // Arm extensions. let Extension = ArmIntegerDotProductInt8 in { diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 6d96ea96cd371..d45777ca127d6 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -115,7 +115,7 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { return *AttrInfoMap[A.getParsedKind()]; // If this is an ignored attribute then return an appropriate ParsedAttrInfo. - static ParsedAttrInfo IgnoredParsedAttrInfo( + static const ParsedAttrInfo IgnoredParsedAttrInfo( AttributeCommonInfo::IgnoredAttribute); if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) return IgnoredParsedAttrInfo; @@ -140,7 +140,7 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { return *Ptr; // If we failed to find a match then return a default ParsedAttrInfo. - static ParsedAttrInfo DefaultParsedAttrInfo( + static const ParsedAttrInfo DefaultParsedAttrInfo( AttributeCommonInfo::UnknownAttribute); return DefaultParsedAttrInfo; } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index ff11e97c5783b..a4131e16d3f5a 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1522,48 +1522,63 @@ class DeferredDiagnosticsEmitter } void visitUsedDecl(SourceLocation Loc, Decl *D) { - if (auto *FD = dyn_cast(D)) { - FunctionDecl *Caller = UseStack.empty() ? nullptr : UseStack.back(); - auto IsKnownEmitted = S.getEmissionStatus(FD, /*Final=*/true) == - Sema::FunctionEmissionStatus::Emitted; - if (!Caller) - ShouldEmit = IsKnownEmitted; - if ((!ShouldEmit && !S.getLangOpts().OpenMP && !Caller) || - S.shouldIgnoreInHostDeviceCheck(FD) || Visited.count(D)) - return; - // Finalize analysis of OpenMP-specific constructs. - if (Caller && S.LangOpts.OpenMP && UseStack.size() == 1) - S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); - // Finalize analysis of SYCL-specific constructs. - if (Caller && S.LangOpts.SYCLIsDevice) - S.finalizeSYCLDelayedAnalysis(Caller, FD, Loc); - if (Caller) - S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; - if (ShouldEmit || InOMPDeviceContext) - S.emitDeferredDiags(FD, Caller); - Visited.insert(D); - UseStack.push_back(FD); - if (auto *S = FD->getBody()) { - this->Visit(S); - } - UseStack.pop_back(); - Visited.erase(D); - } else if (auto *VD = dyn_cast(D)) { - if (auto *Init = VD->getInit()) { - if (S.LangOpts.SYCLIsDevice) - return; - auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD); - bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost || - *DevTy == OMPDeclareTargetDeclAttr::DT_Any); - if (IsDev) - ++InOMPDeviceContext; - this->Visit(Init); - if (IsDev) - --InOMPDeviceContext; - } - } else + if (isa(D)) + return; + if (auto *FD = dyn_cast(D)) + checkFunc(Loc, FD); + else Inherited::visitUsedDecl(Loc, D); } + + void checkVar(VarDecl *VD) { + assert(VD->isFileVarDecl() && + "Should only check file-scope variables"); + if (auto *Init = VD->getInit()) { + auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD); + bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost || + *DevTy == OMPDeclareTargetDeclAttr::DT_Any); + if (IsDev) + ++InOMPDeviceContext; + this->Visit(Init); + if (IsDev) + --InOMPDeviceContext; + } + } + + void checkFunc(SourceLocation Loc, FunctionDecl *FD) { + FunctionDecl *Caller = UseStack.empty() ? nullptr : UseStack.back(); + auto IsKnownEmitted = S.getEmissionStatus(FD, /*Final=*/true) == + Sema::FunctionEmissionStatus::Emitted; + if (!Caller) + ShouldEmit = IsKnownEmitted; + if ((!ShouldEmit && !S.getLangOpts().OpenMP && !Caller) || + S.shouldIgnoreInHostDeviceCheck(FD) || Visited.count(FD)) + return; + // Finalize analysis of OpenMP-specific constructs. + if (Caller && S.LangOpts.OpenMP && UseStack.size() == 1) + S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); + // Finalize analysis of SYCL-specific constructs. + if (Caller && S.LangOpts.SYCLIsDevice) + S.finalizeSYCLDelayedAnalysis(Caller, FD, Loc); + if (Caller) + S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; + if (ShouldEmit || InOMPDeviceContext) + S.emitDeferredDiags(FD, Caller); + Visited.insert(FD); + UseStack.push_back(FD); + if (auto *S = FD->getBody()) { + this->Visit(S); + } + UseStack.pop_back(); + Visited.erase(FD); + } + + void checkRecordedDecl(Decl *D) { + if (auto *FD = dyn_cast(D)) + checkFunc(SourceLocation(), FD); + else + checkVar(cast(D)); + } }; } // namespace @@ -1579,7 +1594,7 @@ void Sema::emitDeferredDiags() { DeferredDiagnosticsEmitter DDE(*this); for (auto D : DeclsToCheckForDeferredDiags) - DDE.visitUsedDecl(SourceLocation(), D); + DDE.checkRecordedDecl(D); } // In CUDA, there are some constructs which may appear in semantically-valid diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 6ba404034a86b..00d47faec8a5b 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -9,6 +9,7 @@ // This file defines the code-completion semantic actions. // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTConcept.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -16,8 +17,11 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/QualTypeNames.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Specifiers.h" @@ -4746,6 +4750,369 @@ static RecordDecl *getAsRecordDecl(const QualType BaseType) { return nullptr; } +namespace { +// Collects completion-relevant information about a concept-constrainted type T. +// In particular, examines the constraint expressions to find members of T. +// +// The design is very simple: we walk down each constraint looking for +// expressions of the form T.foo(). +// If we're extra lucky, the return type is specified. +// We don't do any clever handling of && or || in constraint expressions, we +// take members from both branches. +// +// For example, given: +// template concept X = requires (T t, string& s) { t.print(s); }; +// template void foo(U u) { u.^ } +// We want to suggest the inferred member function 'print(string)'. +// We see that u has type U, so X holds. +// X requires t.print(s) to be valid, where t has type U (substituted for T). +// By looking at the CallExpr we find the signature of print(). +// +// While we tend to know in advance which kind of members (access via . -> ::) +// we want, it's simpler just to gather them all and post-filter. +// +// FIXME: some of this machinery could be used for non-concept type-parms too, +// enabling completion for type parameters based on other uses of that param. +// +// FIXME: there are other cases where a type can be constrained by a concept, +// e.g. inside `if constexpr(ConceptSpecializationExpr) { ... }` +class ConceptInfo { +public: + // Describes a likely member of a type, inferred by concept constraints. + // Offered as a code completion for T. T-> and T:: contexts. + struct Member { + // Always non-null: we only handle members with ordinary identifier names. + const IdentifierInfo *Name = nullptr; + // Set for functions we've seen called. + // We don't have the declared parameter types, only the actual types of + // arguments we've seen. These are still valuable, as it's hard to render + // a useful function completion with neither parameter types nor names! + llvm::Optional> ArgTypes; + // Whether this is accessed as T.member, T->member, or T::member. + enum AccessOperator { + Colons, + Arrow, + Dot, + } Operator = Dot; + // What's known about the type of a variable or return type of a function. + const TypeConstraint *ResultType = nullptr; + // FIXME: also track: + // - kind of entity (function/variable/type), to expose structured results + // - template args kinds/types, as a proxy for template params + + // For now we simply return these results as "pattern" strings. + CodeCompletionString *render(Sema &S, CodeCompletionAllocator &Alloc, + CodeCompletionTUInfo &Info) const { + CodeCompletionBuilder B(Alloc, Info); + // Result type + if (ResultType) { + std::string AsString; + { + llvm::raw_string_ostream OS(AsString); + QualType ExactType = deduceType(*ResultType); + if (!ExactType.isNull()) + ExactType.print(OS, getCompletionPrintingPolicy(S)); + else + ResultType->print(OS, getCompletionPrintingPolicy(S)); + } + B.AddResultTypeChunk(Alloc.CopyString(AsString)); + } + // Member name + B.AddTypedTextChunk(Alloc.CopyString(Name->getName())); + // Function argument list + if (ArgTypes) { + B.AddChunk(clang::CodeCompletionString::CK_LeftParen); + bool First = true; + for (QualType Arg : *ArgTypes) { + if (First) + First = false; + else { + B.AddChunk(clang::CodeCompletionString::CK_Comma); + B.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace); + } + B.AddPlaceholderChunk(Alloc.CopyString( + Arg.getAsString(getCompletionPrintingPolicy(S)))); + } + B.AddChunk(clang::CodeCompletionString::CK_RightParen); + } + return B.TakeString(); + } + }; + + // BaseType is the type parameter T to infer members from. + // T must be accessible within S, as we use it to find the template entity + // that T is attached to in order to gather the relevant constraints. + ConceptInfo(const TemplateTypeParmType &BaseType, Scope *S) { + auto *TemplatedEntity = getTemplatedEntity(BaseType.getDecl(), S); + for (const Expr *E : constraintsForTemplatedEntity(TemplatedEntity)) + believe(E, &BaseType); + } + + std::vector members() { + std::vector Results; + for (const auto &E : this->Results) + Results.push_back(E.second); + llvm::sort(Results, [](const Member &L, const Member &R) { + return L.Name->getName() < R.Name->getName(); + }); + return Results; + } + +private: + // Infer members of T, given that the expression E (dependent on T) is true. + void believe(const Expr *E, const TemplateTypeParmType *T) { + if (!E || !T) + return; + if (auto *CSE = dyn_cast(E)) { + // If the concept is + // template concept CD = f(); + // And the concept specialization is + // CD + // Then we're substituting T for B, so we want to make f() true + // by adding members to B - i.e. believe(f(), B); + // + // For simplicity: + // - we don't attempt to substitute int for A + // - when T is used in other ways (like CD) we ignore it + ConceptDecl *CD = CSE->getNamedConcept(); + TemplateParameterList *Params = CD->getTemplateParameters(); + unsigned Index = 0; + for (const auto &Arg : CSE->getTemplateArguments()) { + if (Index >= Params->size()) + break; // Won't happen in valid code. + if (isApprox(Arg, T)) { + auto *TTPD = dyn_cast(Params->getParam(Index)); + if (!TTPD) + continue; + // T was used as an argument, and bound to the parameter TT. + auto *TT = cast(TTPD->getTypeForDecl()); + // So now we know the constraint as a function of TT is true. + believe(CD->getConstraintExpr(), TT); + // (concepts themselves have no associated constraints to require) + } + + ++Index; + } + } else if (auto *BO = dyn_cast(E)) { + // For A && B, we can infer members from both branches. + // For A || B, the union is still more useful than the intersection. + if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { + believe(BO->getLHS(), T); + believe(BO->getRHS(), T); + } + } else if (auto *RE = dyn_cast(E)) { + // A requires(){...} lets us infer members from each requirement. + for (const concepts::Requirement *Req : RE->getRequirements()) { + if (!Req->isDependent()) + continue; // Can't tell us anything about T. + // Now Req cannot a substitution-error: those aren't dependent. + + if (auto *TR = dyn_cast(Req)) { + // Do a full traversal so we get `foo` from `typename T::foo::bar`. + QualType AssertedType = TR->getType()->getType(); + ValidVisitor(this, T).TraverseType(AssertedType); + } else if (auto *ER = dyn_cast(Req)) { + ValidVisitor Visitor(this, T); + // If we have a type constraint on the value of the expression, + // AND the whole outer expression describes a member, then we'll + // be able to use the constraint to provide the return type. + if (ER->getReturnTypeRequirement().isTypeConstraint()) { + Visitor.OuterType = + ER->getReturnTypeRequirement().getTypeConstraint(); + Visitor.OuterExpr = ER->getExpr(); + } + Visitor.TraverseStmt(ER->getExpr()); + } else if (auto *NR = dyn_cast(Req)) { + believe(NR->getConstraintExpr(), T); + } + } + } + } + + // This visitor infers members of T based on traversing expressions/types + // that involve T. It is invoked with code known to be valid for T. + class ValidVisitor : public RecursiveASTVisitor { + ConceptInfo *Outer; + const TemplateTypeParmType *T; + + CallExpr *Caller = nullptr; + Expr *Callee = nullptr; + + public: + // If set, OuterExpr is constrained by OuterType. + Expr *OuterExpr = nullptr; + const TypeConstraint *OuterType = nullptr; + + ValidVisitor(ConceptInfo *Outer, const TemplateTypeParmType *T) + : Outer(Outer), T(T) { + assert(T); + } + + // In T.foo or T->foo, `foo` is a member function/variable. + bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { + const Type *Base = E->getBaseType().getTypePtr(); + bool IsArrow = E->isArrow(); + if (Base->isPointerType() && IsArrow) { + IsArrow = false; + Base = Base->getPointeeType().getTypePtr(); + } + if (isApprox(Base, T)) + addValue(E, E->getMember(), IsArrow ? Member::Arrow : Member::Dot); + return true; + } + + // In T::foo, `foo` is a static member function/variable. + bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { + if (E->getQualifier() && isApprox(E->getQualifier()->getAsType(), T)) + addValue(E, E->getDeclName(), Member::Colons); + return true; + } + + // In T::typename foo, `foo` is a type. + bool VisitDependentNameType(DependentNameType *DNT) { + const auto *Q = DNT->getQualifier(); + if (Q && isApprox(Q->getAsType(), T)) + addType(DNT->getIdentifier()); + return true; + } + + // In T::foo::bar, `foo` must be a type. + // VisitNNS() doesn't exist, and TraverseNNS isn't always called :-( + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSL) { + if (NNSL) { + NestedNameSpecifier *NNS = NNSL.getNestedNameSpecifier(); + const auto *Q = NNS->getPrefix(); + if (Q && isApprox(Q->getAsType(), T)) + addType(NNS->getAsIdentifier()); + } + // FIXME: also handle T::foo::bar + return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNSL); + } + + // FIXME also handle T::foo + + // Track the innermost caller/callee relationship so we can tell if a + // nested expr is being called as a function. + bool VisitCallExpr(CallExpr *CE) { + Caller = CE; + Callee = CE->getCallee(); + return true; + } + + private: + void addResult(Member &&M) { + auto R = Outer->Results.try_emplace(M.Name); + Member &O = R.first->second; + // Overwrite existing if the new member has more info. + // The preference of . vs :: vs -> is fairly arbitrary. + if (/*Inserted*/ R.second || + std::make_tuple(M.ArgTypes.hasValue(), M.ResultType != nullptr, + M.Operator) > std::make_tuple(O.ArgTypes.hasValue(), + O.ResultType != nullptr, + O.Operator)) + O = std::move(M); + } + + void addType(const IdentifierInfo *Name) { + if (!Name) + return; + Member M; + M.Name = Name; + M.Operator = Member::Colons; + addResult(std::move(M)); + } + + void addValue(Expr *E, DeclarationName Name, + Member::AccessOperator Operator) { + if (!Name.isIdentifier()) + return; + Member Result; + Result.Name = Name.getAsIdentifierInfo(); + Result.Operator = Operator; + // If this is the callee of an immediately-enclosing CallExpr, then + // treat it as a method, otherwise it's a variable. + if (Caller != nullptr && Callee == E) { + Result.ArgTypes.emplace(); + for (const auto *Arg : Caller->arguments()) + Result.ArgTypes->push_back(Arg->getType()); + if (Caller == OuterExpr) { + Result.ResultType = OuterType; + } + } else { + if (E == OuterExpr) + Result.ResultType = OuterType; + } + addResult(std::move(Result)); + } + }; + + static bool isApprox(const TemplateArgument &Arg, const Type *T) { + return Arg.getKind() == TemplateArgument::Type && + isApprox(Arg.getAsType().getTypePtr(), T); + } + + static bool isApprox(const Type *T1, const Type *T2) { + return T1 && T2 && + T1->getCanonicalTypeUnqualified() == + T2->getCanonicalTypeUnqualified(); + } + + // Returns the DeclContext immediately enclosed by the template parameter + // scope. For primary templates, this is the templated (e.g.) CXXRecordDecl. + // For specializations, this is e.g. ClassTemplatePartialSpecializationDecl. + static DeclContext *getTemplatedEntity(const TemplateTypeParmDecl *D, + Scope *S) { + if (D == nullptr) + return nullptr; + Scope *Inner = nullptr; + while (S) { + if (S->isTemplateParamScope() && S->isDeclScope(D)) + return Inner ? Inner->getEntity() : nullptr; + Inner = S; + S = S->getParent(); + } + return nullptr; + } + + // Gets all the type constraint expressions that might apply to the type + // variables associated with DC (as returned by getTemplatedEntity()). + static SmallVector + constraintsForTemplatedEntity(DeclContext *DC) { + SmallVector Result; + if (DC == nullptr) + return Result; + // Primary templates can have constraints. + if (const auto *TD = cast(DC)->getDescribedTemplate()) + TD->getAssociatedConstraints(Result); + // Partial specializations may have constraints. + if (const auto *CTPSD = + dyn_cast(DC)) + CTPSD->getAssociatedConstraints(Result); + if (const auto *VTPSD = dyn_cast(DC)) + VTPSD->getAssociatedConstraints(Result); + return Result; + } + + // Attempt to find the unique type satisfying a constraint. + // This lets us show e.g. `int` instead of `std::same_as`. + static QualType deduceType(const TypeConstraint &T) { + // Assume a same_as return type constraint is std::same_as or equivalent. + // In this case the return type is T. + DeclarationName DN = T.getNamedConcept()->getDeclName(); + if (DN.isIdentifier() && DN.getAsIdentifierInfo()->isStr("same_as")) + if (const auto *Args = T.getTemplateArgsAsWritten()) + if (Args->getNumTemplateArgs() == 1) { + const auto &Arg = Args->arguments().front().getArgument(); + if (Arg.getKind() == TemplateArgument::Type) + return Arg.getAsType(); + } + return {}; + } + + llvm::DenseMap Results; +}; +} // namespace + void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, @@ -4802,15 +5169,31 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, if (const PointerType *Ptr = BaseType->getAs()) { BaseType = Ptr->getPointeeType(); BaseKind = VK_LValue; - } else if (BaseType->isObjCObjectPointerType()) - /*Do nothing*/; - else + } else if (BaseType->isObjCObjectPointerType() || + BaseType->isTemplateTypeParmType()) { + // Both cases (dot/arrow) handled below. + } else { return false; + } } if (RecordDecl *RD = getAsRecordDecl(BaseType)) { AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind, RD, std::move(AccessOpFixIt)); + } else if (const auto *TTPT = + dyn_cast(BaseType.getTypePtr())) { + auto Operator = + IsArrow ? ConceptInfo::Member::Arrow : ConceptInfo::Member::Dot; + for (const auto &R : ConceptInfo(*TTPT, S).members()) { + if (R.Operator != Operator) + continue; + CodeCompletionResult Result( + R.render(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo())); + if (AccessOpFixIt) + Result.FixIts.push_back(*AccessOpFixIt); + Results.AddResult(std::move(Result)); + } } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { // Objective-C property reference. AddedPropertiesSet AddedProperties; @@ -5446,13 +5829,14 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // Always pretend to enter a context to ensure that a dependent type // resolves to a dependent record. DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true); - if (!Ctx) - return; // Try to instantiate any non-dependent declaration contexts before - // we look in them. - if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx)) - return; + // we look in them. Bail out if we fail. + NestedNameSpecifier *NNS = SS.getScopeRep(); + if (NNS != nullptr && SS.isValid() && !NNS->isDependent()) { + if (Ctx == nullptr || RequireCompleteDeclContext(SS, Ctx)) + return; + } ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CC); @@ -5462,21 +5846,34 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. - NestedNameSpecifier *NNS = SS.getScopeRep(); + // FIXME: results is always empty, this appears to be dead. if (!Results.empty() && NNS->isDependent()) Results.AddResult("template"); + // If the scope is a concept-constrained type parameter, infer nested + // members based on the constraints. + if (const auto *TTPT = + dyn_cast_or_null(NNS->getAsType())) { + for (const auto &R : ConceptInfo(*TTPT, S).members()) { + if (R.Operator != ConceptInfo::Member::Colons) + continue; + Results.AddResult(CodeCompletionResult( + R.render(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo()))); + } + } + // Add calls to overridden virtual functions, if there are any. // // FIXME: This isn't wonderful, because we don't know whether we're actually // in a context that permits expressions. This is a general issue with // qualified-id completions. - if (!EnteringContext) + if (Ctx && !EnteringContext) MaybeAddOverrideCalls(*this, Ctx, Results); Results.ExitScope(); - if (CodeCompleter->includeNamespaceLevelDecls() || - (!Ctx->isNamespace() && !Ctx->isTranslationUnit())) { + if (Ctx && + (CodeCompleter->includeNamespaceLevelDecls() || !Ctx->isFileContext())) { CodeCompletionDeclConsumer Consumer(Results, Ctx, BaseType); LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, /*IncludeGlobalScope=*/true, diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 6dc9e342beb92..5ed0bbd6041d1 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -502,8 +502,9 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { return nullptr; auto *ScopeInfo = getCurFunction(); - // Build a list of arguments, based on the coroutine functions arguments, - // that will be passed to the promise type's constructor. + + // Build a list of arguments, based on the coroutine function's arguments, + // that if present will be passed to the promise type's constructor. llvm::SmallVector CtorArgExprs; // Add implicit object parameter. @@ -519,6 +520,7 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { } } + // Add the coroutine function's parameters. auto &Moves = ScopeInfo->CoroutineParameterMoves; for (auto *PD : FD->parameters()) { if (PD->getType()->isDependentType()) @@ -540,28 +542,33 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { CtorArgExprs.push_back(RefExpr.get()); } - // Create an initialization sequence for the promise type using the - // constructor arguments, wrapped in a parenthesized list expression. - Expr *PLE = ParenListExpr::Create(Context, FD->getLocation(), - CtorArgExprs, FD->getLocation()); - InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); - InitializationKind Kind = InitializationKind::CreateForInit( - VD->getLocation(), /*DirectInit=*/true, PLE); - InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs, - /*TopLevelOfInitList=*/false, - /*TreatUnavailableAsInvalid=*/false); - - // Attempt to initialize the promise type with the arguments. - // If that fails, fall back to the promise type's default constructor. - if (InitSeq) { - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs); - if (Result.isInvalid()) { - VD->setInvalidDecl(); - } else if (Result.get()) { - VD->setInit(MaybeCreateExprWithCleanups(Result.get())); - VD->setInitStyle(VarDecl::CallInit); - CheckCompleteVariableDeclaration(VD); - } + // If we have a non-zero number of constructor arguments, try to use them. + // Otherwise, fall back to the promise type's default constructor. + if (!CtorArgExprs.empty()) { + // Create an initialization sequence for the promise type using the + // constructor arguments, wrapped in a parenthesized list expression. + Expr *PLE = ParenListExpr::Create(Context, FD->getLocation(), + CtorArgExprs, FD->getLocation()); + InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); + InitializationKind Kind = InitializationKind::CreateForInit( + VD->getLocation(), /*DirectInit=*/true, PLE); + InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs, + /*TopLevelOfInitList=*/false, + /*TreatUnavailableAsInvalid=*/false); + + // Attempt to initialize the promise type with the arguments. + // If that fails, fall back to the promise type's default constructor. + if (InitSeq) { + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs); + if (Result.isInvalid()) { + VD->setInvalidDecl(); + } else if (Result.get()) { + VD->setInit(MaybeCreateExprWithCleanups(Result.get())); + VD->setInitStyle(VarDecl::CallInit); + CheckCompleteVariableDeclaration(VD); + } + } else + ActOnUninitializedDecl(VD); } else ActOnUninitializedDecl(VD); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 04b231109c9d4..98de799415a0e 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2734,6 +2734,11 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { // honored it. ++I; continue; + } else if (isa(NewAttribute)) { + // We allow to add OMP[Begin]DeclareVariantAttr to be added to + // declarations after defintions. + ++I; + continue; } S.Diag(NewAttribute->getLocation(), @@ -12265,7 +12270,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setInitStyle(VarDecl::ListInit); } - if (LangOpts.OpenMP && VDecl->hasGlobalStorage()) + if (LangOpts.OpenMP && VDecl->isFileVarDecl()) DeclsToCheckForDeferredDiags.push_back(VDecl); CheckCompleteVariableDeclaration(VDecl); } @@ -13582,9 +13587,28 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); + // Check if we are in an `omp begin/end declare variant` scope. If we are, and + // we define a non-templated function definition, we will create a declaration + // instead (=BaseFD), and emit the definition with a mangled name afterwards. + // The base function declaration will have the equivalent of an `omp declare + // variant` annotation which specifies the mangled definition as a + // specialization function under the OpenMP context defined as part of the + // `omp begin declare variant`. + FunctionDecl *BaseFD = nullptr; + if (LangOpts.OpenMP && isInOpenMPDeclareVariantScope() && + TemplateParameterLists.empty()) + BaseFD = ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( + ParentScope, D); + D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); - return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); + Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); + + if (BaseFD) + ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( + cast(Dcl), BaseFD); + + return Dcl; } void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) { @@ -16161,6 +16185,10 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth) { + assert(BitWidth); + if (BitWidth->containsErrors()) + return ExprError(); + // Default to true; that shouldn't confuse checks for emptiness if (ZeroWidth) *ZeroWidth = true; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index deb3a66630244..71d923431ad6f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7523,6 +7523,16 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttributeWithExclusions(S, D, AL); break; + case ParsedAttr::AT_CUDADeviceBuiltinSurfaceType: + handleSimpleAttributeWithExclusions(S, D, + AL); + break; + case ParsedAttr::AT_CUDADeviceBuiltinTextureType: + handleSimpleAttributeWithExclusions(S, D, + AL); + break; case ParsedAttr::AT_GNUInline: handleGNUInlineAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 23d099a9f2e88..2b4f445bfa215 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5877,6 +5877,123 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S, } } +static void checkCUDADeviceBuiltinSurfaceClassTemplate(Sema &S, + CXXRecordDecl *Class) { + bool ErrorReported = false; + auto reportIllegalClassTemplate = [&ErrorReported](Sema &S, + ClassTemplateDecl *TD) { + if (ErrorReported) + return; + S.Diag(TD->getLocation(), + diag::err_cuda_device_builtin_surftex_cls_template) + << /*surface*/ 0 << TD; + ErrorReported = true; + }; + + ClassTemplateDecl *TD = Class->getDescribedClassTemplate(); + if (!TD) { + auto *SD = dyn_cast(Class); + if (!SD) { + S.Diag(Class->getLocation(), + diag::err_cuda_device_builtin_surftex_ref_decl) + << /*surface*/ 0 << Class; + S.Diag(Class->getLocation(), + diag::note_cuda_device_builtin_surftex_should_be_template_class) + << Class; + return; + } + TD = SD->getSpecializedTemplate(); + } + + TemplateParameterList *Params = TD->getTemplateParameters(); + unsigned N = Params->size(); + + if (N != 2) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_n_args) + << TD << 2; + } + if (N > 0 && !isa(Params->getParam(0))) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*1st*/ 0 << /*type*/ 0; + } + if (N > 1) { + auto *NTTP = dyn_cast(Params->getParam(1)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*2nd*/ 1 << /*integer*/ 1; + } + } +} + +static void checkCUDADeviceBuiltinTextureClassTemplate(Sema &S, + CXXRecordDecl *Class) { + bool ErrorReported = false; + auto reportIllegalClassTemplate = [&ErrorReported](Sema &S, + ClassTemplateDecl *TD) { + if (ErrorReported) + return; + S.Diag(TD->getLocation(), + diag::err_cuda_device_builtin_surftex_cls_template) + << /*texture*/ 1 << TD; + ErrorReported = true; + }; + + ClassTemplateDecl *TD = Class->getDescribedClassTemplate(); + if (!TD) { + auto *SD = dyn_cast(Class); + if (!SD) { + S.Diag(Class->getLocation(), + diag::err_cuda_device_builtin_surftex_ref_decl) + << /*texture*/ 1 << Class; + S.Diag(Class->getLocation(), + diag::note_cuda_device_builtin_surftex_should_be_template_class) + << Class; + return; + } + TD = SD->getSpecializedTemplate(); + } + + TemplateParameterList *Params = TD->getTemplateParameters(); + unsigned N = Params->size(); + + if (N != 3) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_n_args) + << TD << 3; + } + if (N > 0 && !isa(Params->getParam(0))) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*1st*/ 0 << /*type*/ 0; + } + if (N > 1) { + auto *NTTP = dyn_cast(Params->getParam(1)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*2nd*/ 1 << /*integer*/ 1; + } + } + if (N > 2) { + auto *NTTP = dyn_cast(Params->getParam(2)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*3rd*/ 2 << /*integer*/ 1; + } + } +} + void Sema::checkClassLevelCodeSegAttribute(CXXRecordDecl *Class) { // Mark any compiler-generated routines with the implicit code_seg attribute. for (auto *Method : Class->methods()) { @@ -6657,6 +6774,13 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // is especially required for cases like vtable assumption loads. MarkVTableUsed(Record->getInnerLocStart(), Record); } + + if (getLangOpts().CUDA) { + if (Record->hasAttr()) + checkCUDADeviceBuiltinSurfaceClassTemplate(*this, Record); + else if (Record->hasAttr()) + checkCUDADeviceBuiltinTextureClassTemplate(*this, Record); + } } /// Look up the special member function that would be called by a special diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 53c62a1a40177..0dc0c68205fbb 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1299,6 +1299,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) { // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: case Expr::OMPArraySectionExprClass: + case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: case Expr::BinaryOperatorClass: case Expr::DependentCoawaitExprClass: case Expr::CompoundAssignOperatorClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index bd7db4a9aca18..7a0db866cb0e8 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4816,6 +4816,206 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, VK_LValue, OK_Ordinary, ColonLoc, RBLoc); } +ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef Dims, + ArrayRef Brackets) { + if (Base->getType()->isPlaceholderType()) { + ExprResult Result = CheckPlaceholderExpr(Base); + if (Result.isInvalid()) + return ExprError(); + Result = DefaultLvalueConversion(Result.get()); + if (Result.isInvalid()) + return ExprError(); + Base = Result.get(); + } + QualType BaseTy = Base->getType(); + // Delay analysis of the types/expressions if instantiation/specialization is + // required. + if (!BaseTy->isPointerType() && Base->isTypeDependent()) + return OMPArrayShapingExpr::Create(Context, Context.DependentTy, Base, + LParenLoc, RParenLoc, Dims, Brackets); + if (!BaseTy->isPointerType() || + (!Base->isTypeDependent() && + BaseTy->getPointeeType()->isIncompleteType())) + return ExprError(Diag(Base->getExprLoc(), + diag::err_omp_non_pointer_type_array_shaping_base) + << Base->getSourceRange()); + + SmallVector NewDims; + bool ErrorFound = false; + for (Expr *Dim : Dims) { + if (Dim->getType()->isPlaceholderType()) { + ExprResult Result = CheckPlaceholderExpr(Dim); + if (Result.isInvalid()) { + ErrorFound = true; + continue; + } + Result = DefaultLvalueConversion(Result.get()); + if (Result.isInvalid()) { + ErrorFound = true; + continue; + } + Dim = Result.get(); + } + if (!Dim->isTypeDependent()) { + ExprResult Result = + PerformOpenMPImplicitIntegerConversion(Dim->getExprLoc(), Dim); + if (Result.isInvalid()) { + ErrorFound = true; + Diag(Dim->getExprLoc(), diag::err_omp_typecheck_shaping_not_integer) + << Dim->getSourceRange(); + continue; + } + Dim = Result.get(); + Expr::EvalResult EvResult; + if (!Dim->isValueDependent() && Dim->EvaluateAsInt(EvResult, Context)) { + // OpenMP 5.0, [2.1.4 Array Shaping] + // Each si is an integral type expression that must evaluate to a + // positive integer. + llvm::APSInt Value = EvResult.Val.getInt(); + if (!Value.isStrictlyPositive()) { + Diag(Dim->getExprLoc(), diag::err_omp_shaping_dimension_not_positive) + << Value.toString(/*Radix=*/10, /*Signed=*/true) + << Dim->getSourceRange(); + ErrorFound = true; + continue; + } + } + } + NewDims.push_back(Dim); + } + if (ErrorFound) + return ExprError(); + return OMPArrayShapingExpr::Create(Context, Context.OMPArrayShapingTy, Base, + LParenLoc, RParenLoc, NewDims, Brackets); +} + +ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, + SourceLocation LLoc, SourceLocation RLoc, + ArrayRef Data) { + SmallVector ID; + bool IsCorrect = true; + for (const OMPIteratorData &D : Data) { + TypeSourceInfo *TInfo = nullptr; + SourceLocation StartLoc; + QualType DeclTy; + if (!D.Type.getAsOpaquePtr()) { + // OpenMP 5.0, 2.1.6 Iterators + // In an iterator-specifier, if the iterator-type is not specified then + // the type of that iterator is of int type. + DeclTy = Context.IntTy; + StartLoc = D.DeclIdentLoc; + } else { + DeclTy = GetTypeFromParser(D.Type, &TInfo); + StartLoc = TInfo->getTypeLoc().getBeginLoc(); + } + + bool IsDeclTyDependent = DeclTy->isDependentType() || + DeclTy->containsUnexpandedParameterPack() || + DeclTy->isInstantiationDependentType(); + if (!IsDeclTyDependent) { + if (!DeclTy->isIntegralType(Context) && !DeclTy->isAnyPointerType()) { + // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++ + // The iterator-type must be an integral or pointer type. + Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer) + << DeclTy; + IsCorrect = false; + continue; + } + if (DeclTy.isConstant(Context)) { + // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++ + // The iterator-type must not be const qualified. + Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer) + << DeclTy; + IsCorrect = false; + continue; + } + } + + // Iterator declaration. + assert(D.DeclIdent && "Identifier expected."); + // Always try to create iterator declarator to avoid extra error messages + // about unknown declarations use. + auto *VD = VarDecl::Create(Context, CurContext, StartLoc, D.DeclIdentLoc, + D.DeclIdent, DeclTy, TInfo, SC_None); + VD->setImplicit(); + if (S) { + // Check for conflicting previous declaration. + DeclarationNameInfo NameInfo(VD->getDeclName(), D.DeclIdentLoc); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForVisibleRedeclaration); + Previous.suppressDiagnostics(); + LookupName(Previous, S); + + FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + if (!Previous.empty()) { + NamedDecl *Old = Previous.getRepresentativeDecl(); + Diag(D.DeclIdentLoc, diag::err_redefinition) << VD->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + } else { + PushOnScopeChains(VD, S); + } + } else { + CurContext->addDecl(VD); + } + Expr *Begin = D.Range.Begin; + if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) { + ExprResult BeginRes = + PerformImplicitConversion(Begin, DeclTy, AA_Converting); + Begin = BeginRes.get(); + } + Expr *End = D.Range.End; + if (!IsDeclTyDependent && End && !End->isTypeDependent()) { + ExprResult EndRes = PerformImplicitConversion(End, DeclTy, AA_Converting); + End = EndRes.get(); + } + Expr *Step = D.Range.Step; + if (!IsDeclTyDependent && Step && !Step->isTypeDependent()) { + if (!Step->getType()->isIntegralType(Context)) { + Diag(Step->getExprLoc(), diag::err_omp_iterator_step_not_integral) + << Step << Step->getSourceRange(); + IsCorrect = false; + continue; + } + llvm::APSInt Result; + bool IsConstant = Step->isIntegerConstantExpr(Result, Context); + // OpenMP 5.0, 2.1.6 Iterators, Restrictions + // If the step expression of a range-specification equals zero, the + // behavior is unspecified. + if (IsConstant && Result.isNullValue()) { + Diag(Step->getExprLoc(), diag::err_omp_iterator_step_constant_zero) + << Step << Step->getSourceRange(); + IsCorrect = false; + continue; + } + } + if (!Begin || !End || !IsCorrect) { + IsCorrect = false; + continue; + } + OMPIteratorExpr::IteratorDefinition &IDElem = ID.emplace_back(); + IDElem.IteratorDecl = VD; + IDElem.AssignmentLoc = D.AssignLoc; + IDElem.Range.Begin = Begin; + IDElem.Range.End = End; + IDElem.Range.Step = Step; + IDElem.ColonLoc = D.ColonLoc; + IDElem.SecondColonLoc = D.SecColonLoc; + } + if (!IsCorrect) { + // Invalidate all created iterator declarations if error is found. + for (const OMPIteratorExpr::IteratorDefinition &D : ID) { + if (Decl *ID = D.IteratorDecl) + ID->setInvalidDecl(); + } + return ExprError(); + } + return OMPIteratorExpr::Create(Context, Context.OMPIteratorTy, IteratorKwLoc, + LLoc, RLoc, ID); +} + ExprResult Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc) { @@ -5576,6 +5776,8 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { case BuiltinType::BoundMember: case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: return true; } @@ -5812,6 +6014,10 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, } } + if (LangOpts.OpenMP) + Call = ActOnOpenMPCall(*this, Call, Scope, LParenLoc, ArgExprs, RParenLoc, + ExecConfig); + return Call; } @@ -9219,7 +9425,13 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, // Reject cases where the scalar type is not a constant and has a higher // Order than the vector element type. llvm::APFloat Result(0.0); - bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context); + + // Determine whether this is a constant scalar. In the event that the + // value is dependent (and thus cannot be evaluated by the constant + // evaluator), skip the evaluation. This will then diagnose once the + // expression is instantiated. + bool CstScalar = Scalar->get()->isValueDependent() || + Scalar->get()->EvaluateAsFloat(Result, S.Context); int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy); if (!CstScalar && Order < 0) return true; @@ -16125,9 +16337,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, Func->markUsed(Context); } - - if (LangOpts.OpenMP) - markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse); } /// Directly mark a variable odr-used. Given a choice, prefer to use @@ -18446,6 +18655,13 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { Diag(E->getBeginLoc(), diag::err_omp_array_section_use); return ExprError(); + // Expressions of unknown type. + case BuiltinType::OMPArrayShaping: + return ExprError(Diag(E->getBeginLoc(), diag::err_omp_array_shaping_use)); + + case BuiltinType::OMPIterator: + return ExprError(Diag(E->getBeginLoc(), diag::err_omp_iterator_use)); + // Everything else should be impossible. #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: @@ -18526,8 +18742,8 @@ bool Sema::IsDependentFunctionNameExpr(Expr *E) { ExprResult Sema::CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, ArrayRef SubExprs) { - // RecoveryExpr is type-dependent to suppress bogus diagnostics and this trick - // does not work in C. + // FIXME: enable it for C++, RecoveryExpr is type-dependent to suppress + // bogus diagnostics and this trick does not work in C. // FIXME: use containsErrors() to suppress unwanted diags in C. if (!Context.getLangOpts().RecoveryAST) return ExprError(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 11cc43a16db1a..f663b1d436594 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -35,6 +35,8 @@ #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include + using namespace clang; using namespace llvm::omp; @@ -62,14 +64,15 @@ class DSAStackTy { struct DSAVarData { OpenMPDirectiveKind DKind = OMPD_unknown; OpenMPClauseKind CKind = OMPC_unknown; + unsigned Modifier = 0; const Expr *RefExpr = nullptr; DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; DSAVarData() = default; DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, const Expr *RefExpr, DeclRefExpr *PrivateCopy, - SourceLocation ImplicitDSALoc) - : DKind(DKind), CKind(CKind), RefExpr(RefExpr), + SourceLocation ImplicitDSALoc, unsigned Modifier) + : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr), PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {} }; using OperatorOffsetTy = @@ -80,6 +83,7 @@ class DSAStackTy { private: struct DSAInfo { OpenMPClauseKind Attributes = OMPC_unknown; + unsigned Modifier = 0; /// Pointer to a reference expression and a flag which shows that the /// variable is marked as lastprivate(true) or not (false). llvm::PointerIntPair RefExpr; @@ -164,6 +168,8 @@ class DSAStackTy { /// List of globals marked as declare target link in this target region /// (isOpenMPTargetExecutionDirective(Directive) == true). llvm::SmallVector DeclareTargetLinkVarDecls; + /// List of decls used in inclusive/exclusive clauses of the scan directive. + llvm::DenseSet> UsedInScanDirective; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : Directive(DKind), DirectiveName(Name), CurScope(CurScope), @@ -469,9 +475,22 @@ class DSAStackTy { /// parent directive. const ValueDecl *getParentLoopControlVariable(unsigned I) const; + /// Marks the specified decl \p D as used in scan directive. + void markDeclAsUsedInScanDirective(ValueDecl *D) { + if (SharingMapTy *Stack = getSecondOnStackOrNull()) + Stack->UsedInScanDirective.insert(D); + } + + /// Checks if the specified declaration was used in the inner scan directive. + bool isUsedInScanDirective(ValueDecl *D) const { + if (const SharingMapTy *Stack = getTopOfStackOrNull()) + return Stack->UsedInScanDirective.count(D) > 0; + return false; + } + /// Adds explicit data sharing attribute to the specified declaration. void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, - DeclRefExpr *PrivateCopy = nullptr); + DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0); /// Adds additional information for the reduction items with the reduction id /// represented as an operator. @@ -1079,6 +1098,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, DVar.PrivateCopy = Data.PrivateCopy; DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; + DVar.Modifier = Data.Modifier; return DVar; } @@ -1226,19 +1246,21 @@ const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const { } void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, - DeclRefExpr *PrivateCopy) { + DeclRefExpr *PrivateCopy, unsigned Modifier) { D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { DSAInfo &Data = Threadprivates[D]; Data.Attributes = A; Data.RefExpr.setPointer(E); Data.PrivateCopy = nullptr; + Data.Modifier = Modifier; } else { DSAInfo &Data = getTopOfStack().SharingMap[D]; assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) || (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) || (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) || (isLoopControlVariable(D).first && A == OMPC_private)); + Data.Modifier = Modifier; if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) { Data.RefExpr.setInt(/*IntVal=*/true); return; @@ -1250,6 +1272,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, Data.PrivateCopy = PrivateCopy; if (PrivateCopy) { DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()]; + Data.Modifier = Modifier; Data.Attributes = A; Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); Data.PrivateCopy = nullptr; @@ -1355,7 +1378,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( "set."); TaskgroupDescriptor = I->TaskgroupReductionRef; return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), - Data.PrivateCopy, I->DefaultAttrLoc); + Data.PrivateCopy, I->DefaultAttrLoc, /*Modifier=*/0); } return DSAVarData(); } @@ -1380,7 +1403,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( "set."); TaskgroupDescriptor = I->TaskgroupReductionRef; return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), - Data.PrivateCopy, I->DefaultAttrLoc); + Data.PrivateCopy, I->DefaultAttrLoc, /*Modifier=*/0); } return DSAVarData(); } @@ -1455,6 +1478,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, if (TI != Threadprivates.end()) { DVar.RefExpr = TI->getSecond().RefExpr.getPointer(); DVar.CKind = OMPC_threadprivate; + DVar.Modifier = TI->getSecond().Modifier; return DVar; } if (VD && VD->hasAttr()) { @@ -1538,15 +1562,18 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, const_iterator EndI = end(); if (FromParent && I != EndI) ++I; - auto It = I->SharingMap.find(D); - if (It != I->SharingMap.end()) { - const DSAInfo &Data = It->getSecond(); - DVar.RefExpr = Data.RefExpr.getPointer(); - DVar.PrivateCopy = Data.PrivateCopy; - DVar.CKind = Data.Attributes; - DVar.ImplicitDSALoc = I->DefaultAttrLoc; - DVar.DKind = I->Directive; - return DVar; + if (I != EndI) { + auto It = I->SharingMap.find(D); + if (It != I->SharingMap.end()) { + const DSAInfo &Data = It->getSecond(); + DVar.RefExpr = Data.RefExpr.getPointer(); + DVar.PrivateCopy = Data.PrivateCopy; + DVar.CKind = Data.Attributes; + DVar.ImplicitDSALoc = I->DefaultAttrLoc; + DVar.DKind = I->Directive; + DVar.Modifier = Data.Modifier; + return DVar; + } } DVar.CKind = OMPC_shared; @@ -1584,6 +1611,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, const_iterator EndI = end(); if (FromParent && I != EndI) ++I; + if (I == EndI) + return DVar; auto It = I->SharingMap.find(D); if (It != I->SharingMap.end()) { const DSAInfo &Data = It->getSecond(); @@ -1592,6 +1621,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; DVar.DKind = I->Directive; + DVar.Modifier = Data.Modifier; } return DVar; @@ -1915,7 +1945,8 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, if (isa(EI->getAssociatedExpression()) || isa(EI->getAssociatedExpression()) || - isa(EI->getAssociatedExpression())) { + isa(EI->getAssociatedExpression()) || + isa(EI->getAssociatedExpression())) { IsVariableAssociatedWithSection = true; // There is nothing more we need to know about this variable. return true; @@ -2244,6 +2275,22 @@ bool Sema::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level, void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } +void Sema::ActOnOpenMPBeginDeclareVariant(SourceLocation Loc, + OMPTraitInfo &TI) { + if (!OMPDeclareVariantScopes.empty()) { + Diag(Loc, diag::warn_nested_declare_variant); + return; + } + OMPDeclareVariantScopes.push_back(OMPDeclareVariantScope(TI)); +} + +void Sema::ActOnOpenMPEndDeclareVariant() { + assert(isInOpenMPDeclareVariantScope() && + "Not in OpenMP declare variant scope!"); + + OMPDeclareVariantScopes.pop_back(); +} + void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, const FunctionDecl *Callee, SourceLocation Loc) { @@ -2299,11 +2346,64 @@ void Sema::EndOpenMPClause() { DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown); } -static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, - ArrayRef Clauses); static std::pair getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, SourceRange &ERange, bool AllowArraySection = false); + +/// Check consistency of the reduction clauses. +static void checkReductionClauses(Sema &S, DSAStackTy *Stack, + ArrayRef Clauses) { + bool InscanFound = false; + SourceLocation InscanLoc; + // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions. + // A reduction clause without the inscan reduction-modifier may not appear on + // a construct on which a reduction clause with the inscan reduction-modifier + // appears. + for (OMPClause *C : Clauses) { + if (C->getClauseKind() != OMPC_reduction) + continue; + auto *RC = cast(C); + if (RC->getModifier() == OMPC_REDUCTION_inscan) { + InscanFound = true; + InscanLoc = RC->getModifierLoc(); + break; + } + } + if (InscanFound) { + for (OMPClause *C : Clauses) { + if (C->getClauseKind() != OMPC_reduction) + continue; + auto *RC = cast(C); + if (RC->getModifier() != OMPC_REDUCTION_inscan) { + S.Diag(RC->getModifier() == OMPC_REDUCTION_unknown + ? RC->getBeginLoc() + : RC->getModifierLoc(), + diag::err_omp_inscan_reduction_expected); + S.Diag(InscanLoc, diag::note_omp_previous_inscan_reduction); + continue; + } + for (Expr *Ref : RC->varlists()) { + assert(Ref && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = Ref; + auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + ValueDecl *D = Res.first; + if (!D) + continue; + if (!Stack->isUsedInScanDirective(getCanonicalDecl(D))) { + S.Diag(Ref->getExprLoc(), + diag::err_omp_reduction_not_inclusive_exclusive) + << Ref->getSourceRange(); + } + } + } + } +} + +static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, + ArrayRef Clauses); static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, bool WithInit); @@ -2380,6 +2480,7 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // Check allocate clauses. if (!CurContext->isDependentContext()) checkAllocateClauses(*this, DSAStack, D->clauses()); + checkReductionClauses(*this, DSAStack, D->clauses()); } DSAStack->pop(); @@ -3127,7 +3228,7 @@ class DSAAttrChecker final : public StmtVisitor { StackComponents, OpenMPClauseKind) { // Variable is used if it has been marked as an array, array - // section or the variable iself. + // section, array shaping or the variable iself. return StackComponents.size() == 1 || std::all_of( std::next(StackComponents.rbegin()), @@ -3138,6 +3239,8 @@ class DSAAttrChecker final : public StmtVisitor { nullptr && (isa( MC.getAssociatedExpression()) || + isa( + MC.getAssociatedExpression()) || isa( MC.getAssociatedExpression())); }); @@ -3295,8 +3398,10 @@ class DSAAttrChecker final : public StmtVisitor { // Do both expressions have the same kind? if (CCI->getAssociatedExpression()->getStmtClass() != SC.getAssociatedExpression()->getStmtClass()) - if (!(isa( - SC.getAssociatedExpression()) && + if (!((isa( + SC.getAssociatedExpression()) || + isa( + SC.getAssociatedExpression())) && isa( CCI->getAssociatedExpression()))) return false; @@ -3788,6 +3893,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_end_declare_target: case OMPD_requires: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -4177,7 +4284,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, if (ParentRegion == OMPD_unknown && !isOpenMPNestingTeamsDirective(CurrentRegion) && CurrentRegion != OMPD_cancellation_point && - CurrentRegion != OMPD_cancel) + CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_scan) return false; if (CurrentRegion == OMPD_cancellation_point || CurrentRegion == OMPD_cancel) { @@ -4298,7 +4405,8 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, NestingProhibited = SemaRef.LangOpts.OpenMP < 50 || (ParentRegion != OMPD_simd && ParentRegion != OMPD_for && - ParentRegion != OMPD_for_simd); + ParentRegion != OMPD_for_simd && ParentRegion != OMPD_parallel_for && + ParentRegion != OMPD_parallel_for_simd); OrphanSeen = ParentRegion == OMPD_unknown; Recommend = ShouldBeInLoopSimdRegion; } @@ -5014,6 +5122,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_simd: case OMPD_requires: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -5435,6 +5545,131 @@ static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto, FD->setParams(Params); } +Sema::OMPDeclareVariantScope::OMPDeclareVariantScope(OMPTraitInfo &TI) + : TI(&TI), NameSuffix(TI.getMangledName()) {} + +FunctionDecl * +Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S, + Declarator &D) { + auto *BaseFD = cast(ActOnDeclarator(S, D)); + OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); + std::string MangledName; + MangledName += D.getIdentifier()->getName(); + MangledName += getOpenMPVariantManglingSeparatorStr(); + MangledName += DVScope.NameSuffix; + IdentifierInfo &VariantII = Context.Idents.get(MangledName); + + VariantII.setMangledOpenMPVariantName(true); + D.SetIdentifier(&VariantII, D.getBeginLoc()); + return BaseFD; +} + +void Sema::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( + FunctionDecl *FD, FunctionDecl *BaseFD) { + // Do not mark function as is used to prevent its emission if this is the + // only place where it is used. + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); + + Expr *VariantFuncRef = DeclRefExpr::Create( + Context, NestedNameSpecifierLoc(), SourceLocation(), FD, + /* RefersToEnclosingVariableOrCapture */ false, + /* NameLoc */ FD->getLocation(), FD->getType(), ExprValueKind::VK_RValue); + + OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); + auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantFuncRef, DVScope.TI); + BaseFD->addAttr(OMPDeclareVariantA); + + BaseFD->setImplicit(true); +} + +ExprResult Sema::ActOnOpenMPCall(Sema &S, ExprResult Call, Scope *Scope, + SourceLocation LParenLoc, + MultiExprArg ArgExprs, + SourceLocation RParenLoc, Expr *ExecConfig) { + // The common case is a regular call we do not want to specialize at all. Try + // to make that case fast by bailing early. + CallExpr *CE = dyn_cast(Call.get()); + if (!CE) + return Call; + + FunctionDecl *CalleeFnDecl = CE->getDirectCallee(); + if (!CalleeFnDecl) + return Call; + + if (!CalleeFnDecl->hasAttr()) + return Call; + + ASTContext &Context = S.getASTContext(); + OMPContext OMPCtx(S.getLangOpts().OpenMPIsDevice, + Context.getTargetInfo().getTriple()); + + SmallVector Exprs; + SmallVector VMIs; + while (CalleeFnDecl) { + for (OMPDeclareVariantAttr *A : + CalleeFnDecl->specific_attrs()) { + Expr *VariantRef = A->getVariantFuncRef(); + + VariantMatchInfo VMI; + OMPTraitInfo &TI = A->getTraitInfo(); + TI.getAsVariantMatchInfo(Context, VMI, /* DeviceSetOnly */ false); + if (!isVariantApplicableInContext(VMI, OMPCtx)) + continue; + + VMIs.push_back(VMI); + Exprs.push_back(VariantRef); + } + + CalleeFnDecl = CalleeFnDecl->getPreviousDecl(); + } + + ExprResult NewCall; + do { + int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx); + if (BestIdx < 0) + return Call; + Expr *BestExpr = cast(Exprs[BestIdx]); + Decl *BestDecl = cast(BestExpr)->getDecl(); + + { + // Try to build a (member) call expression for the current best applicable + // variant expression. We allow this to fail in which case we continue + // with the next best variant expression. The fail case is part of the + // implementation defined behavior in the OpenMP standard when it talks + // about what differences in the function prototypes: "Any differences + // that the specific OpenMP context requires in the prototype of the + // variant from the base function prototype are implementation defined." + // This wording is there to allow the specialized variant to have a + // different type than the base function. This is intended and OK but if + // we cannot create a call the difference is not in the "implementation + // defined range" we allow. + Sema::TentativeAnalysisScope Trap(*this); + + if (auto *SpecializedMethod = dyn_cast(BestDecl)) { + auto *MemberCall = dyn_cast(CE); + BestExpr = MemberExpr::CreateImplicit( + S.Context, MemberCall->getImplicitObjectArgument(), + /* IsArrow */ false, SpecializedMethod, S.Context.BoundMemberTy, + MemberCall->getValueKind(), MemberCall->getObjectKind()); + } + NewCall = S.BuildCallExpr(Scope, BestExpr, LParenLoc, ArgExprs, RParenLoc, + ExecConfig); + if (NewCall.isUsable()) + break; + } + + VMIs.erase(VMIs.begin() + BestIdx); + Exprs.erase(Exprs.begin() + BestIdx); + } while (!VMIs.empty()); + + if (!NewCall.isUsable()) + return Call; + + return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0); +} + Optional> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, Expr *VariantRef, OMPTraitInfo &TI, @@ -5707,25 +5942,6 @@ void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, FD->addAttr(NewAttr); } -void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, - FunctionDecl *Func, - bool MightBeOdrUse) { - assert(LangOpts.OpenMP && "Expected OpenMP mode."); - - if (!Func->isDependentContext() && Func->hasAttrs()) { - for (OMPDeclareVariantAttr *A : - Func->specific_attrs()) { - // TODO: add checks for active OpenMP context where possible. - Expr *VariantRef = A->getVariantFuncRef(); - auto *DRE = cast(VariantRef->IgnoreParenImpCasts()); - auto *F = cast(DRE->getDecl()); - if (!F->isDefined() && F->isTemplateInstantiation()) - InstantiateFunctionDefinition(Loc, F->getFirstDecl()); - MarkFunctionReferenced(Loc, F, MightBeOdrUse); - } - } -} - StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -11221,6 +11437,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -11293,6 +11511,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -11370,6 +11590,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11444,6 +11666,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11519,6 +11743,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11593,6 +11819,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11666,6 +11894,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11742,6 +11972,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -12826,7 +13058,7 @@ OMPClause *Sema::ActOnOpenMPDestroyClause(SourceLocation StartLoc, } OMPClause *Sema::ActOnOpenMPVarListClause( - OpenMPClauseKind Kind, ArrayRef VarList, Expr *TailExpr, + OpenMPClauseKind Kind, ArrayRef VarList, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, @@ -12876,13 +13108,13 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown && "Unexpected linear modifier."); Res = ActOnOpenMPLinearClause( - VarList, TailExpr, StartLoc, LParenLoc, + VarList, DepModOrTailExpr, StartLoc, LParenLoc, static_cast(ExtraModifier), ExtraModifierLoc, ColonLoc, EndLoc); break; case OMPC_aligned: - Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAlignedClause(VarList, DepModOrTailExpr, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_copyin: Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -12897,8 +13129,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown && "Unexpected depend modifier."); Res = ActOnOpenMPDependClause( - static_cast(ExtraModifier), ExtraModifierLoc, - ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + DepModOrTailExpr, static_cast(ExtraModifier), + ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown && @@ -12923,8 +13155,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs); break; case OMPC_allocate: - Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAllocateClause(DepModOrTailExpr, VarList, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_nontemporal: Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -13971,9 +14203,11 @@ struct ReductionData { SmallVector ExprCaptures; /// List of postupdate expressions. SmallVector ExprPostUpdates; + /// Reduction modifier. + unsigned RedModifier = 0; ReductionData() = delete; /// Reserves required memory for the reduction data. - ReductionData(unsigned Size) { + ReductionData(unsigned Size, unsigned Modifier = 0) : RedModifier(Modifier) { Vars.reserve(Size); Privates.reserve(Size); LHSs.reserve(Size); @@ -14613,8 +14847,8 @@ static bool actOnOMPReductionKindClause( if (ClauseKind == OMPC_in_reduction) { SourceRange ParentSR; BinaryOperatorKind ParentBOK; - const Expr *ParentReductionOp; - Expr *ParentBOKTD, *ParentReductionOpTD; + const Expr *ParentReductionOp = nullptr; + Expr *ParentBOKTD = nullptr, *ParentReductionOpTD = nullptr; DSAStackTy::DSAVarData ParentBOKDSA = Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK, ParentBOKTD); @@ -14623,13 +14857,9 @@ static bool actOnOMPReductionKindClause( D, ParentSR, ParentReductionOp, ParentReductionOpTD); bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown; bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown; - if (!IsParentBOK && !IsParentReductionOp) { - S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction); - continue; - } if ((DeclareReductionRef.isUnset() && IsParentReductionOp) || - (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK || - IsParentReductionOp) { + (DeclareReductionRef.isUsable() && IsParentBOK) || + (IsParentBOK && BOK != ParentBOK) || IsParentReductionOp) { bool EmitError = true; if (IsParentReductionOp && DeclareReductionRef.isUsable()) { llvm::FoldingSetNodeID RedId, ParentRedId; @@ -14652,7 +14882,6 @@ static bool actOnOMPReductionKindClause( } } TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD; - assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined."); } DeclRefExpr *Ref = nullptr; @@ -14691,7 +14920,8 @@ static bool actOnOMPReductionKindClause( } // All reduction items are still marked as reduction (to do not increase // code base size). - Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); + Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref, + RD.RedModifier); if (CurrDir == OMPD_taskgroup) { if (DeclareReductionRef.isUsable()) Stack->addTaskgroupReductionData(D, ReductionIdRange, @@ -14718,8 +14948,22 @@ OMPClause *Sema::ActOnOpenMPReductionClause( << getOpenMPClauseName(OMPC_reduction); return nullptr; } + // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions + // A reduction clause with the inscan reduction-modifier may only appear on a + // worksharing-loop construct, a worksharing-loop SIMD construct, a simd + // construct, a parallel worksharing-loop construct or a parallel + // worksharing-loop SIMD construct. + if (Modifier == OMPC_REDUCTION_inscan && + (DSAStack->getCurrentDirective() != OMPD_for && + DSAStack->getCurrentDirective() != OMPD_for_simd && + DSAStack->getCurrentDirective() != OMPD_simd && + DSAStack->getCurrentDirective() != OMPD_parallel_for && + DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) { + Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction); + return nullptr; + } - ReductionData RD(VarList.size()); + ReductionData RD(VarList.size(), Modifier); if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, @@ -15403,7 +15647,7 @@ OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, } OMPClause * -Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, +Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { @@ -15425,12 +15669,26 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, Except.push_back(OMPC_DEPEND_sink); if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) Except.push_back(OMPC_DEPEND_depobj); + std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) + ? "depend modifier(iterator) or " + : ""; Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << getListOfPossibleValues(OMPC_depend, /*First=*/0, - /*Last=*/OMPC_DEPEND_unknown, Except) + << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, + Except) << getOpenMPClauseName(OMPC_depend); return nullptr; } + if (DepModifier && + (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) { + Diag(DepModifier->getExprLoc(), + diag::err_omp_depend_sink_source_with_modifier); + return nullptr; + } + if (DepModifier && + !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator)) + Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator); + SmallVector Vars; DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); @@ -15590,7 +15848,8 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, (OMPDependTFound && DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr())) { Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << 1 << RefExpr->getSourceRange(); + << (LangOpts.OpenMP >= 50 ? 1 : 0) << 1 + << RefExpr->getSourceRange(); continue; } @@ -15603,6 +15862,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, ->isPointerType() && !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); continue; } @@ -15613,8 +15873,10 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts()); } - if (!Res.isUsable() && !isa(SimpleExpr)) { + if (!Res.isUsable() && !isa(SimpleExpr) && + !isa(SimpleExpr)) { Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); continue; } @@ -15635,8 +15897,8 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, return nullptr; auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, - DepKind, DepLoc, ColonLoc, Vars, - TotalDepCount.getZExtValue()); + DepModifier, DepKind, DepLoc, ColonLoc, + Vars, TotalDepCount.getZExtValue()); if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) && DSAStack->isParentOrderedRegion()) DSAStack->addDoacrossDependClause(C, OpsOffs); @@ -16046,6 +16308,15 @@ class MapBaseChecker final : public StmtVisitor { Components.emplace_back(OASE, nullptr); return RelevantExpr || Visit(E); } + bool VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + Expr *Base = E->getBase(); + + // Record the component - we don't have any declaration associated. + Components.emplace_back(E, nullptr); + + return Visit(Base->IgnoreParenImpCasts()); + } + bool VisitUnaryOperator(UnaryOperator *UO) { if (SemaRef.getLangOpts().OpenMP < 50 || !UO->isLValue() || UO->getOpcode() != UO_Deref) { @@ -16171,9 +16442,11 @@ static bool checkMapConflicts( // variable in map clauses of the same construct. if (CurrentRegionOnly && (isa(CI->getAssociatedExpression()) || - isa(CI->getAssociatedExpression())) && + isa(CI->getAssociatedExpression()) || + isa(CI->getAssociatedExpression())) && (isa(SI->getAssociatedExpression()) || - isa(SI->getAssociatedExpression()))) { + isa(SI->getAssociatedExpression()) || + isa(SI->getAssociatedExpression()))) { SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(), diag::err_omp_multiple_array_items_in_map_clause) << CI->getAssociatedExpression()->getSourceRange(); @@ -16205,6 +16478,9 @@ static bool checkMapConflicts( const Expr *E = OASE->getBase()->IgnoreParenImpCasts(); Type = OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + } else if (const auto *OASE = dyn_cast( + SI->getAssociatedExpression())) { + Type = OASE->getBase()->getType()->getPointeeType(); } if (Type.isNull() || Type->isAnyPointerType() || checkArrayExpressionDoesNotReferToWholeSize( @@ -16667,6 +16943,7 @@ static void checkMappableExpressionList( QualType Type; auto *ASE = dyn_cast(VE->IgnoreParens()); auto *OASE = dyn_cast(VE->IgnoreParens()); + auto *OAShE = dyn_cast(VE->IgnoreParens()); if (ASE) { Type = ASE->getType().getNonReferenceType(); } else if (OASE) { @@ -16677,6 +16954,8 @@ static void checkMappableExpressionList( else Type = BaseType->getPointeeType(); Type = Type.getNonReferenceType(); + } else if (OAShE) { + Type = OAShE->getBase()->getType()->getPointeeType(); } else { Type = VE->getType(); } @@ -16780,7 +17059,7 @@ OMPClause *Sema::ActOnOpenMPMapClause( OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown}; - SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers]; + SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers]; // Process map-type-modifiers, flag errors for duplicate modifiers. unsigned Count = 0; @@ -16790,7 +17069,7 @@ OMPClause *Sema::ActOnOpenMPMapClause( Diag(MapTypeModifiersLoc[I], diag::err_omp_duplicate_map_type_modifier); continue; } - assert(Count < OMPMapClause::NumberOfModifiers && + assert(Count < NumberOfOMPMapClauseModifiers && "Modifiers exceed the allowed number of map type modifiers"); Modifiers[Count] = MapTypeModifiers[I]; ModifiersLoc[Count] = MapTypeModifiersLoc[I]; @@ -18021,6 +18300,19 @@ OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef VarList, if (!D) continue; + const DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/true); + // OpenMP 5.0, 2.9.6, scan Directive, Restrictions. + // A list item that appears in the inclusive or exclusive clause must appear + // in a reduction clause with the inscan modifier on the enclosing + // worksharing-loop, worksharing-loop SIMD, or simd construct. + if (DVar.CKind != OMPC_reduction || + DVar.Modifier != OMPC_REDUCTION_inscan) + Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction) + << RefExpr->getSourceRange(); + + if (DSAStack->getParentDirective() != OMPD_unknown) + DSAStack->markDeclAsUsedInScanDirective(D); Vars.push_back(RefExpr); } @@ -18049,6 +18341,21 @@ OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef VarList, if (!D) continue; + OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective(); + DSAStackTy::DSAVarData DVar; + if (ParentDirective != OMPD_unknown) + DVar = DSAStack->getTopDSA(D, /*FromParent=*/true); + // OpenMP 5.0, 2.9.6, scan Directive, Restrictions. + // A list item that appears in the inclusive or exclusive clause must appear + // in a reduction clause with the inscan modifier on the enclosing + // worksharing-loop, worksharing-loop SIMD, or simd construct. + if (ParentDirective == OMPD_unknown || DVar.CKind != OMPC_reduction || + DVar.Modifier != OMPC_REDUCTION_inscan) { + Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction) + << RefExpr->getSourceRange(); + } else { + DSAStack->markDeclAsUsedInScanDirective(D); + } Vars.push_back(RefExpr); } diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 87c3c264b472e..6a541f9693ec2 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -1663,6 +1663,8 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { bop->getType(), bop->getValueKind(), bop->getObjectKind(), bop->getOperatorLoc(), FPOptions()); + } else if (isa(syntax)) { + return syntax; } else { assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject)); return stripOpaqueValuesFromPseudoObjectRef(*this, syntax); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 72b8b4765aa64..b2179c78176e5 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -334,6 +334,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } else if (const PseudoObjectExpr *POE = dyn_cast(E)) { const Expr *Source = POE->getSyntacticForm(); + // Handle the actually selected call of an OpenMP specialized call. + if (LangOpts.OpenMP && isa(Source) && + POE->getNumSemanticExprs() == 1 && + isa(POE->getSemanticExpr(0))) + return DiagnoseUnusedExprResult(POE->getSemanticExpr(0)); if (isa(Source)) DiagID = diag::warn_unused_container_subscript_expr; else diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f95b16c1cbaed..342262522e615 100755 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -205,7 +205,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization, SourceLocation(), - &AssumedTemplate, Disambiguation)) + &AssumedTemplate, + /*AllowTypoCorrection=*/!Disambiguation)) return TNK_Non_template; if (AssumedTemplate != AssumedTemplateKind::None) { @@ -371,12 +372,15 @@ bool Sema::LookupTemplateName(LookupResult &Found, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, - SourceLocation TemplateKWLoc, + RequiredTemplateKind RequiredTemplate, AssumedTemplateKind *ATK, - bool Disambiguation) { + bool AllowTypoCorrection) { if (ATK) *ATK = AssumedTemplateKind::None; + if (SS.isInvalid()) + return true; + Found.setTemplateNameLookup(true); // Determine where to perform name lookup @@ -386,7 +390,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. - assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); + assert(SS.isEmpty() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); IsDependent = !LookupCtx && ObjectType->isDependentType(); assert((IsDependent || !ObjectType->isIncompleteType() || @@ -412,11 +416,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, Found.clear(); return false; } - } else if (SS.isSet()) { + } else if (SS.isNotEmpty()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); - IsDependent = !LookupCtx; + IsDependent = !LookupCtx && isDependentScopeSpecifier(SS); // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) @@ -443,7 +447,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } - if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) { + if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) { // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the @@ -470,7 +474,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, if (Found.isAmbiguous()) return false; - if (ATK && !SS.isSet() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) { + if (ATK && SS.isEmpty() && ObjectType.isNull() && + !RequiredTemplate.hasTemplateKeyword()) { // C++2a [temp.names]p2: // A name is also considered to refer to a template if it is an // unqualified-id followed by a < and name lookup finds either one or more @@ -496,7 +501,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, } } - if (Found.empty() && !IsDependent && !Disambiguation) { + if (Found.empty() && !IsDependent && AllowTypoCorrection) { // If we did not find any names, and this is not a disambiguation, attempt // to correct any typos. DeclarationName Name = Found.getLookupName(); @@ -542,9 +547,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, // If a 'template' keyword was used, a lookup that finds only non-template // names is an error. - if (ExampleLookupResult && TemplateKWLoc.isValid()) { + if (ExampleLookupResult && RequiredTemplate) { Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template) - << Found.getLookupName() << SS.getRange(); + << Found.getLookupName() << SS.getRange() + << RequiredTemplate.hasTemplateKeyword() + << RequiredTemplate.getTemplateKeywordLoc(); Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(), diag::note_template_kw_refers_to_non_template) << Found.getLookupName(); @@ -3470,6 +3477,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, DTN->getIdentifier(), TemplateArgs); + if (Name.getAsAssumedTemplateName() && + resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) + return QualType(); + TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa(Template) || isa(Template) || isa(Template)) { @@ -4623,21 +4634,28 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs); } -/// Form a dependent template name. +/// Form a template name from a name that is syntactically required to name a +/// template, either due to use of the 'template' keyword or because a name in +/// this syntactic context is assumed to name a template (C++ [temp.names]p2-4). +/// +/// This action forms a template name given the name of the template and its +/// optional scope specifier. This is used when the 'template' keyword is used +/// or when the parsing context unambiguously treats a following '<' as +/// introducing a template argument list. Note that this may produce a +/// non-dependent template name if we can perform the lookup now and identify +/// the named template. /// -/// This action forms a dependent template name given the template -/// name and its (presumably dependent) scope specifier. For -/// example, given "MetaFun::template apply", the scope specifier \p -/// SS will be "MetaFun::", \p TemplateKWLoc contains the location +/// For example, given "x.MetaFun::template apply", the scope specifier +/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location /// of the "template" keyword, and "apply" is the \p Name. -TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, - CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - const UnqualifiedId &Name, - ParsedType ObjectType, - bool EnteringContext, - TemplateTy &Result, - bool AllowInjectedClassName) { +TemplateNameKind Sema::ActOnTemplateName(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Result, + bool AllowInjectedClassName) { if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent()) Diag(TemplateKWLoc, getLangOpts().CPlusPlus11 ? @@ -4645,95 +4663,115 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, diag::ext_template_outside_of_template) << FixItHint::CreateRemoval(TemplateKWLoc); + if (SS.isInvalid()) + return TNK_Non_template; + + // Figure out where isTemplateName is going to look. DeclContext *LookupCtx = nullptr; - if (SS.isSet()) + if (SS.isNotEmpty()) LookupCtx = computeDeclContext(SS, EnteringContext); - if (!LookupCtx && ObjectType) - LookupCtx = computeDeclContext(ObjectType.get()); - if (LookupCtx) { - // C++0x [temp.names]p5: - // If a name prefixed by the keyword template is not the name of - // a template, the program is ill-formed. [Note: the keyword - // template may not be applied to non-template members of class - // templates. -end note ] [ Note: as is the case with the - // typename prefix, the template prefix is allowed in cases - // where it is not strictly necessary; i.e., when the - // nested-name-specifier or the expression on the left of the -> - // or . is not dependent on a template-parameter, or the use - // does not appear in the scope of a template. -end note] - // - // Note: C++03 was more strict here, because it banned the use of - // the "template" keyword prior to a template-name that was not a - // dependent name. C++ DR468 relaxed this requirement (the - // "template" keyword is now permitted). We follow the C++0x - // rules, even in C++03 mode with a warning, retroactively applying the DR. - bool MemberOfUnknownSpecialization; - TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, - ObjectType, EnteringContext, Result, - MemberOfUnknownSpecialization); - if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) { - // This is a dependent template. Handle it below. - } else if (TNK == TNK_Non_template) { - // Do the lookup again to determine if this is a "nothing found" case or - // a "not a template" case. FIXME: Refactor isTemplateName so we don't - // need to do this. - DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); - LookupResult R(*this, DNI.getName(), Name.getBeginLoc(), - LookupOrdinaryName); - bool MOUS; - if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, - MOUS, TemplateKWLoc) && !R.isAmbiguous()) + else if (ObjectType) + LookupCtx = computeDeclContext(GetTypeFromParser(ObjectType)); + + // C++0x [temp.names]p5: + // If a name prefixed by the keyword template is not the name of + // a template, the program is ill-formed. [Note: the keyword + // template may not be applied to non-template members of class + // templates. -end note ] [ Note: as is the case with the + // typename prefix, the template prefix is allowed in cases + // where it is not strictly necessary; i.e., when the + // nested-name-specifier or the expression on the left of the -> + // or . is not dependent on a template-parameter, or the use + // does not appear in the scope of a template. -end note] + // + // Note: C++03 was more strict here, because it banned the use of + // the "template" keyword prior to a template-name that was not a + // dependent name. C++ DR468 relaxed this requirement (the + // "template" keyword is now permitted). We follow the C++0x + // rules, even in C++03 mode with a warning, retroactively applying the DR. + bool MemberOfUnknownSpecialization; + TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, + ObjectType, EnteringContext, Result, + MemberOfUnknownSpecialization); + if (TNK != TNK_Non_template) { + // We resolved this to a (non-dependent) template name. Return it. + auto *LookupRD = dyn_cast_or_null(LookupCtx); + if (!AllowInjectedClassName && SS.isNotEmpty() && LookupRD && + Name.getKind() == UnqualifiedIdKind::IK_Identifier && + Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) { + // C++14 [class.qual]p2: + // In a lookup in which function names are not ignored and the + // nested-name-specifier nominates a class C, if the name specified + // [...] is the injected-class-name of C, [...] the name is instead + // considered to name the constructor + // + // We don't get here if naming the constructor would be valid, so we + // just reject immediately and recover by treating the + // injected-class-name as naming the template. + Diag(Name.getBeginLoc(), + diag::ext_out_of_line_qualified_id_type_names_constructor) + << Name.Identifier + << 0 /*injected-class-name used as template name*/ + << TemplateKWLoc.isValid(); + } + return TNK; + } + + if (!MemberOfUnknownSpecialization) { + // Didn't find a template name, and the lookup wasn't dependent. + // Do the lookup again to determine if this is a "nothing found" case or + // a "not a template" case. FIXME: Refactor isTemplateName so we don't + // need to do this. + DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); + LookupResult R(*this, DNI.getName(), Name.getBeginLoc(), + LookupOrdinaryName); + bool MOUS; + // Tell LookupTemplateName that we require a template so that it diagnoses + // cases where it finds a non-template. + RequiredTemplateKind RTK = TemplateKWLoc.isValid() + ? RequiredTemplateKind(TemplateKWLoc) + : TemplateNameIsRequired; + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS, + RTK, nullptr, /*AllowTypoCorrection=*/false) && + !R.isAmbiguous()) { + if (LookupCtx) Diag(Name.getBeginLoc(), diag::err_no_member) << DNI.getName() << LookupCtx << SS.getRange(); - return TNK_Non_template; - } else { - // We found something; return it. - auto *LookupRD = dyn_cast(LookupCtx); - if (!AllowInjectedClassName && SS.isSet() && LookupRD && - Name.getKind() == UnqualifiedIdKind::IK_Identifier && - Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) { - // C++14 [class.qual]p2: - // In a lookup in which function names are not ignored and the - // nested-name-specifier nominates a class C, if the name specified - // [...] is the injected-class-name of C, [...] the name is instead - // considered to name the constructor - // - // We don't get here if naming the constructor would be valid, so we - // just reject immediately and recover by treating the - // injected-class-name as naming the template. - Diag(Name.getBeginLoc(), - diag::ext_out_of_line_qualified_id_type_names_constructor) - << Name.Identifier - << 0 /*injected-class-name used as template name*/ - << 1 /*'template' keyword was used*/; - } - return TNK; + else + Diag(Name.getBeginLoc(), diag::err_undeclared_use) + << DNI.getName() << SS.getRange(); } + return TNK_Non_template; } NestedNameSpecifier *Qualifier = SS.getScopeRep(); switch (Name.getKind()) { case UnqualifiedIdKind::IK_Identifier: - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, - Name.Identifier)); + Result = TemplateTy::make( + Context.getDependentTemplateName(Qualifier, Name.Identifier)); return TNK_Dependent_template_name; case UnqualifiedIdKind::IK_OperatorFunctionId: - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, - Name.OperatorFunctionId.Operator)); + Result = TemplateTy::make(Context.getDependentTemplateName( + Qualifier, Name.OperatorFunctionId.Operator)); return TNK_Function_template; case UnqualifiedIdKind::IK_LiteralOperatorId: - llvm_unreachable("literal operator id cannot have a dependent scope"); + // This is a kind of template name, but can never occur in a dependent + // scope (literal operators can only be declared at namespace scope). + break; default: break; } - Diag(Name.getBeginLoc(), diag::err_template_kw_refers_to_non_template) + // This name cannot possibly name a dependent template. Diagnose this now + // rather than building a dependent template name that can never be valid. + Diag(Name.getBeginLoc(), + diag::err_template_kw_refers_to_dependent_non_template) << GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange() - << TemplateKWLoc; + << TemplateKWLoc.isValid() << TemplateKWLoc; return TNK_Non_template; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f84d9b010d739..589ff1ac7565f 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1693,6 +1693,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; } + // FIXME: we want resulting declarations to be marked invalid, but claiming + // the type is invalid is too strong - e.g. it causes ActOnTypeName to return + // a null type. + if (Result->containsErrors()) + declarator.setInvalidType(); + if (S.getLangOpts().OpenCL && S.checkOpenCLDisabledTypeDeclSpec(DS, Result)) declarator.setInvalidType(true); @@ -2453,28 +2459,34 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, VectorType::GenericVector); - unsigned VectorSize = static_cast(VecSize.getZExtValue() * 8); + // vecSize is specified in bytes - convert to bits. + if (!VecSize.isIntN(61)) { + // Bit size will overflow uint64. + Diag(AttrLoc, diag::err_attribute_size_too_large) + << SizeExpr->getSourceRange(); + return QualType(); + } + uint64_t VectorSizeBits = VecSize.getZExtValue() * 8; unsigned TypeSize = static_cast(Context.getTypeSize(CurType)); - if (VectorSize == 0) { + if (VectorSizeBits == 0) { Diag(AttrLoc, diag::err_attribute_zero_size) << SizeExpr->getSourceRange(); return QualType(); } - // vecSize is specified in bytes - convert to bits. - if (VectorSize % TypeSize) { + if (VectorSizeBits % TypeSize) { Diag(AttrLoc, diag::err_attribute_invalid_size) << SizeExpr->getSourceRange(); return QualType(); } - if (VectorType::isVectorSizeTooLarge(VectorSize / TypeSize)) { + if (VectorSizeBits / TypeSize > std::numeric_limits::max()) { Diag(AttrLoc, diag::err_attribute_size_too_large) << SizeExpr->getSourceRange(); return QualType(); } - return Context.getVectorType(CurType, VectorSize / TypeSize, + return Context.getVectorType(CurType, VectorSizeBits / TypeSize, VectorType::GenericVector); } @@ -2506,6 +2518,11 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } + if (!vecSize.isIntN(32)) { + Diag(AttrLoc, diag::err_attribute_size_too_large) + << ArraySize->getSourceRange(); + return QualType(); + } // Unlike gcc's vector_size attribute, the size is specified as the // number of elements, not the number of bytes. unsigned vectorSize = static_cast(vecSize.getZExtValue()); @@ -2516,12 +2533,6 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } - if (VectorType::isVectorSizeTooLarge(vectorSize)) { - Diag(AttrLoc, diag::err_attribute_size_too_large) - << ArraySize->getSourceRange(); - return QualType(); - } - return Context.getExtVectorType(T, vectorSize); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 552723d06d942..0b38b958151c2 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1846,12 +1846,13 @@ class TreeTransform { /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause * - RebuildOMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, - SourceLocation ColonLoc, ArrayRef VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList, - StartLoc, LParenLoc, EndLoc); + RebuildOMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPDependClause(DepModifier, DepKind, DepLoc, + ColonLoc, VarList, StartLoc, + LParenLoc, EndLoc); } /// Build a new OpenMP 'device' clause. @@ -2383,6 +2384,29 @@ class TreeTransform { ColonLoc, Length, RBracketLoc); } + /// Build a new array shaping expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef Dims, + ArrayRef BracketsRanges) { + return getSema().ActOnOMPArrayShapingExpr(Base, LParenLoc, RParenLoc, Dims, + BracketsRanges); + } + + /// Build a new iterator expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildOMPIteratorExpr( + SourceLocation IteratorKwLoc, SourceLocation LLoc, SourceLocation RLoc, + ArrayRef Data) { + return getSema().ActOnOMPIteratorExpr(/*Scope=*/nullptr, IteratorKwLoc, + LLoc, RLoc, Data); + } + /// Build a new call expression. /// /// By default, performs semantic analysis to build the new expression. @@ -9286,6 +9310,13 @@ template OMPClause * TreeTransform::TransformOMPDependClause(OMPDependClause *C) { llvm::SmallVector Vars; + Expr *DepModifier = C->getModifier(); + if (DepModifier) { + ExprResult DepModRes = getDerived().TransformExpr(DepModifier); + if (DepModRes.isInvalid()) + return nullptr; + DepModifier = DepModRes.get(); + } Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); @@ -9294,8 +9325,9 @@ TreeTransform::TransformOMPDependClause(OMPDependClause *C) { Vars.push_back(EVar.get()); } return getDerived().RebuildOMPDependClause( - C->getDependencyKind(), C->getDependencyLoc(), C->getColonLoc(), Vars, - C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + DepModifier, C->getDependencyKind(), C->getDependencyLoc(), + C->getColonLoc(), Vars, C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc()); } template @@ -10024,6 +10056,90 @@ TreeTransform::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { Length.get(), E->getRBracketLoc()); } +template +ExprResult +TreeTransform::TransformOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + SmallVector Dims; + bool ErrorFound = false; + for (Expr *Dim : E->getDimensions()) { + ExprResult DimRes = getDerived().TransformExpr(Dim); + if (DimRes.isInvalid()) { + ErrorFound = true; + continue; + } + Dims.push_back(DimRes.get()); + } + + if (ErrorFound) + return ExprError(); + return getDerived().RebuildOMPArrayShapingExpr(Base.get(), E->getLParenLoc(), + E->getRParenLoc(), Dims, + E->getBracketsRanges()); +} + +template +ExprResult +TreeTransform::TransformOMPIteratorExpr(OMPIteratorExpr *E) { + unsigned NumIterators = E->numOfIterators(); + SmallVector Data(NumIterators); + + bool ErrorFound = false; + bool NeedToRebuild = getDerived().AlwaysRebuild(); + for (unsigned I = 0; I < NumIterators; ++I) { + auto *D = cast(E->getIteratorDecl(I)); + Data[I].DeclIdent = D->getIdentifier(); + Data[I].DeclIdentLoc = D->getLocation(); + if (D->getLocation() == D->getBeginLoc()) { + assert(SemaRef.Context.hasSameType(D->getType(), SemaRef.Context.IntTy) && + "Implicit type must be int."); + } else { + TypeSourceInfo *TSI = getDerived().TransformType(D->getTypeSourceInfo()); + QualType DeclTy = getDerived().TransformType(D->getType()); + Data[I].Type = SemaRef.CreateParsedType(DeclTy, TSI); + } + OMPIteratorExpr::IteratorRange Range = E->getIteratorRange(I); + ExprResult Begin = getDerived().TransformExpr(Range.Begin); + ExprResult End = getDerived().TransformExpr(Range.End); + ExprResult Step = getDerived().TransformExpr(Range.Step); + ErrorFound = ErrorFound || + !(!D->getTypeSourceInfo() || (Data[I].Type.getAsOpaquePtr() && + !Data[I].Type.get().isNull())) || + Begin.isInvalid() || End.isInvalid() || Step.isInvalid(); + if (ErrorFound) + continue; + Data[I].Range.Begin = Begin.get(); + Data[I].Range.End = End.get(); + Data[I].Range.Step = Step.get(); + Data[I].AssignLoc = E->getAssignLoc(I); + Data[I].ColonLoc = E->getColonLoc(I); + Data[I].SecColonLoc = E->getSecondColonLoc(I); + NeedToRebuild = + NeedToRebuild || + (D->getTypeSourceInfo() && Data[I].Type.get().getTypePtrOrNull() != + D->getType().getTypePtrOrNull()) || + Range.Begin != Data[I].Range.Begin || Range.End != Data[I].Range.End || + Range.Step != Data[I].Range.Step; + } + if (ErrorFound) + return ExprError(); + if (!NeedToRebuild) + return E; + + ExprResult Res = getDerived().RebuildOMPIteratorExpr( + E->getIteratorKwLoc(), E->getLParenLoc(), E->getRParenLoc(), Data); + if (!Res.isUsable()) + return Res; + auto *IE = cast(Res.get()); + for (unsigned I = 0; I < NumIterators; ++I) + getDerived().transformedLocalDecl(E->getIteratorDecl(I), + IE->getIteratorDecl(I)); + return Res; +} + template ExprResult TreeTransform::TransformCallExpr(CallExpr *E) { @@ -13688,11 +13804,10 @@ TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; - getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, - SS, TemplateKWLoc, TemplateName, - ParsedType::make(ObjectType), - /*EnteringContext=*/false, - Template, AllowInjectedClassName); + getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, + TemplateName, ParsedType::make(ObjectType), + /*EnteringContext=*/false, Template, + AllowInjectedClassName); return Template.get(); } @@ -13709,11 +13824,9 @@ TreeTransform::RebuildTemplateName(CXXScopeSpec &SS, SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc }; Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations); Sema::TemplateTy Template; - getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, - SS, TemplateKWLoc, Name, - ParsedType::make(ObjectType), - /*EnteringContext=*/false, - Template, AllowInjectedClassName); + getSema().ActOnTemplateName( + /*Scope=*/nullptr, SS, TemplateKWLoc, Name, ParsedType::make(ObjectType), + /*EnteringContext=*/false, Template, AllowInjectedClassName); return Template.get(); } diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index f93f1f77405d3..566bda2d71f70 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -243,6 +243,12 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::OMPArraySection: ID = PREDEF_TYPE_OMP_ARRAY_SECTION; break; + case BuiltinType::OMPArrayShaping: + ID = PREDEF_TYPE_OMP_ARRAY_SHAPING; + break; + case BuiltinType::OMPIterator: + ID = PREDEF_TYPE_OMP_ITERATOR; + break; } return TypeIdx(ID); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index c2d28f4362418..7d84f1108c854 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6957,6 +6957,12 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_OMP_ARRAY_SECTION: T = Context.OMPArraySectionTy; break; + case PREDEF_TYPE_OMP_ARRAY_SHAPING: + T = Context.OMPArraySectionTy; + break; + case PREDEF_TYPE_OMP_ITERATOR: + T = Context.OMPIteratorTy; + break; #define SVE_TYPE(Name, Id, SingletonId) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ @@ -8511,7 +8517,7 @@ unsigned ASTReader::getModuleFileID(ModuleFile *F) { llvm::Optional ASTReader::getSourceDescriptor(unsigned ID) { - if (const Module *M = getSubmodule(ID)) + if (Module *M = getSubmodule(ID)) return ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. @@ -12304,6 +12310,7 @@ void OMPClauseReader::VisitOMPDepobjClause(OMPDepobjClause *C) { void OMPClauseReader::VisitOMPDependClause(OMPDependClause *C) { C->setLParenLoc(Record.readSourceLocation()); + C->setModifier(Record.readSubExpr()); C->setDependencyKind( static_cast(Record.readInt())); C->setDependencyLoc(Record.readSourceLocation()); @@ -12328,7 +12335,7 @@ void OMPClauseReader::VisitOMPDeviceClause(OMPDeviceClause *C) { void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) { C->setLParenLoc(Record.readSourceLocation()); - for (unsigned I = 0; I < OMPMapClause::NumberOfModifiers; ++I) { + for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) { C->setMapTypeModifier( I, static_cast(Record.readInt())); C->setMapTypeModifierLoc(I, Record.readSourceLocation()); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 5d9033e379777..2c915659ad7c5 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -50,6 +50,7 @@ #include "clang/Lex/Token.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTRecordReader.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -107,7 +108,7 @@ namespace clang { /// The number of record fields required for the Expr class /// itself. static const unsigned NumExprFields = - NumStmtFields + ExprDependenceBits + 3; + NumStmtFields + llvm::BitWidth + 3; /// Read and initialize a ExplicitTemplateArgumentList structure. void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, @@ -910,6 +911,42 @@ void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { E->setRBracketLoc(readSourceLocation()); } +void ASTStmtReader::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + VisitExpr(E); + unsigned NumDims = Record.readInt(); + E->setBase(Record.readSubExpr()); + SmallVector Dims(NumDims); + for (unsigned I = 0; I < NumDims; ++I) + Dims[I] = Record.readSubExpr(); + E->setDimensions(Dims); + SmallVector SRs(NumDims); + for (unsigned I = 0; I < NumDims; ++I) + SRs[I] = readSourceRange(); + E->setBracketsRanges(SRs); + E->setLParenLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); +} + +void ASTStmtReader::VisitOMPIteratorExpr(OMPIteratorExpr *E) { + VisitExpr(E); + unsigned NumIters = Record.readInt(); + E->setIteratorKwLoc(readSourceLocation()); + E->setLParenLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); + for (unsigned I = 0; I < NumIters; ++I) { + E->setIteratorDeclaration(I, Record.readDeclRef()); + E->setAssignmentLoc(I, readSourceLocation()); + Expr *Begin = Record.readSubExpr(); + Expr *End = Record.readSubExpr(); + Expr *Step = Record.readSubExpr(); + SourceLocation ColonLoc = readSourceLocation(); + SourceLocation SecColonLoc; + if (Step) + SecColonLoc = readSourceLocation(); + E->setIteratorRange(I, Begin, ColonLoc, End, SecColonLoc, Step); + } +} + void ASTStmtReader::VisitCallExpr(CallExpr *E) { VisitExpr(E); unsigned NumArgs = Record.readInt(); @@ -2865,6 +2902,16 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) OMPArraySectionExpr(Empty); break; + case EXPR_OMP_ARRAY_SHAPING: + S = OMPArrayShapingExpr::CreateEmpty( + Context, Record[ASTStmtReader::NumExprFields]); + break; + + case EXPR_OMP_ITERATOR: + S = OMPIteratorExpr::CreateEmpty(Context, + Record[ASTStmtReader::NumExprFields]); + break; + case EXPR_CALL: S = CallExpr::CreateEmpty( Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], Empty); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index f7c58ed11d9f4..89ba7e6239657 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6379,6 +6379,7 @@ void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getNumLoops()); Record.AddSourceLocation(C->getLParenLoc()); + Record.AddStmt(C->getModifier()); Record.push_back(C->getDependencyKind()); Record.AddSourceLocation(C->getDependencyLoc()); Record.AddSourceLocation(C->getColonLoc()); @@ -6402,7 +6403,7 @@ void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) { Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); - for (unsigned I = 0; I < OMPMapClause::NumberOfModifiers; ++I) { + for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) { Record.push_back(C->getMapTypeModifier(I)); Record.AddSourceLocation(C->getMapTypeModifierLoc(I)); } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index d64e2330850a1..ee8bb3e1d4626 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -774,6 +774,39 @@ void ASTStmtWriter::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { Code = serialization::EXPR_OMP_ARRAY_SECTION; } +void ASTStmtWriter::VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + VisitExpr(E); + Record.push_back(E->getDimensions().size()); + Record.AddStmt(E->getBase()); + for (Expr *Dim : E->getDimensions()) + Record.AddStmt(Dim); + for (SourceRange SR : E->getBracketsRanges()) + Record.AddSourceRange(SR); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + Code = serialization::EXPR_OMP_ARRAY_SHAPING; +} + +void ASTStmtWriter::VisitOMPIteratorExpr(OMPIteratorExpr *E) { + VisitExpr(E); + Record.push_back(E->numOfIterators()); + Record.AddSourceLocation(E->getIteratorKwLoc()); + Record.AddSourceLocation(E->getLParenLoc()); + Record.AddSourceLocation(E->getRParenLoc()); + for (unsigned I = 0, End = E->numOfIterators(); I < End; ++I) { + Record.AddDeclRef(E->getIteratorDecl(I)); + Record.AddSourceLocation(E->getAssignLoc(I)); + OMPIteratorExpr::IteratorRange Range = E->getIteratorRange(I); + Record.AddStmt(Range.Begin); + Record.AddStmt(Range.End); + Record.AddStmt(Range.Step); + Record.AddSourceLocation(E->getColonLoc(I)); + if (Range.Step) + Record.AddSourceLocation(E->getSecondColonLoc(I)); + } + Code = serialization::EXPR_OMP_ITERATOR; +} + void ASTStmtWriter::VisitCallExpr(CallExpr *E) { VisitExpr(E); Record.push_back(E->getNumArgs()); diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index 002233e49bb06..d869796b82c12 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -57,6 +57,11 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { } } + // Errors that do not prevent the PCH from being written should not cause the + // overall compilation to fail either. + if (AllowASTWithErrors) + PP.getDiagnostics().getClient()->clear(); + // Emit the PCH file to the Buffer. assert(SemaPtr && "No Sema?"); Buffer->Signature = diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp index 2ef50a727ece4..fb1a407dbdf7f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp @@ -186,6 +186,6 @@ void ento::registerAnalysisOrderChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterAnalysisOrderChecker(const LangOptions &LO) { +bool ento::shouldRegisterAnalysisOrderChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index 634492655228a..c06604b6cffef 100644 --- a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp @@ -140,6 +140,6 @@ void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterAnalyzerStatsChecker(const LangOptions &LO) { +bool ento::shouldRegisterAnalyzerStatsChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp index 716571c592771..59163c1f31fa9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -92,6 +92,6 @@ void ento::registerArrayBoundChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterArrayBoundChecker(const LangOptions &LO) { +bool ento::shouldRegisterArrayBoundChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index 192a3a1a805f8..7c264bba4b6a7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -356,6 +356,6 @@ void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterArrayBoundCheckerV2(const LangOptions &LO) { +bool ento::shouldRegisterArrayBoundCheckerV2(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 325952fe4ed4d..918c6e361381e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -1243,7 +1243,7 @@ void ento::registerNilArgChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterNilArgChecker(const LangOptions &LO) { +bool ento::shouldRegisterNilArgChecker(const CheckerManager &mgr) { return true; } @@ -1251,7 +1251,7 @@ void ento::registerCFNumberChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCFNumberChecker(const LangOptions &LO) { +bool ento::shouldRegisterCFNumberChecker(const CheckerManager &mgr) { return true; } @@ -1259,7 +1259,7 @@ void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCFRetainReleaseChecker(const LangOptions &LO) { +bool ento::shouldRegisterCFRetainReleaseChecker(const CheckerManager &mgr) { return true; } @@ -1267,7 +1267,7 @@ void ento::registerClassReleaseChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterClassReleaseChecker(const LangOptions &LO) { +bool ento::shouldRegisterClassReleaseChecker(const CheckerManager &mgr) { return true; } @@ -1275,7 +1275,7 @@ void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterVariadicMethodTypeChecker(const LangOptions &LO) { +bool ento::shouldRegisterVariadicMethodTypeChecker(const CheckerManager &mgr) { return true; } @@ -1283,7 +1283,7 @@ void ento::registerObjCLoopChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCLoopChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCLoopChecker(const CheckerManager &mgr) { return true; } @@ -1291,6 +1291,6 @@ void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCNonNilReturnValueChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCNonNilReturnValueChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp index 0eb3c3d1d0e6d..2752b37f9b3f6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp @@ -184,6 +184,6 @@ void ento::registerBlockInCriticalSectionChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterBlockInCriticalSectionChecker(const LangOptions &LO) { +bool ento::shouldRegisterBlockInCriticalSectionChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp index a64b1213ba291..6c0caf3c4e78a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp @@ -96,6 +96,6 @@ void ento::registerBoolAssignmentChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterBoolAssignmentChecker(const LangOptions &LO) { +bool ento::shouldRegisterBoolAssignmentChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 51236437329c6..3eeb1e9a3502e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -135,6 +135,6 @@ void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterBuiltinFunctionChecker(const LangOptions &LO) { +bool ento::shouldRegisterBuiltinFunctionChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 15004134bfe68..dcad2264e8cd9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -2430,7 +2430,7 @@ void ento::registerCStringModeling(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterCStringModeling(const LangOptions &LO) { +bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) { return true; } @@ -2441,7 +2441,7 @@ bool ento::shouldRegisterCStringModeling(const LangOptions &LO) { checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name(const LangOptions &LO) { return true; } + bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(CStringNullArg) REGISTER_CHECKER(CStringOutOfBounds) diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index d84fcc69a4925..888724f7ea3b2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -291,6 +291,6 @@ void ento::registerCStringSyntaxChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCStringSyntaxChecker(const LangOptions &LO) { +bool ento::shouldRegisterCStringSyntaxChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp index aada05db2cbc4..24776338ce10b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp @@ -76,6 +76,6 @@ void ento::registerCXXSelfAssignmentChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterCXXSelfAssignmentChecker(const LangOptions &LO) { +bool ento::shouldRegisterCXXSelfAssignmentChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 2fcb765cd4eef..82bc200ba4ce5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -605,7 +605,7 @@ void ento::registerCallAndMessageChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCallAndMessageChecker(const LangOptions &LO) { +bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) { return true; } @@ -615,6 +615,6 @@ void ento::registerCallAndMessageUnInitRefArg(CheckerManager &mgr) { Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckerName(); } -bool ento::shouldRegisterCallAndMessageUnInitRefArg(const LangOptions &LO) { +bool ento::shouldRegisterCallAndMessageUnInitRefArg(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index b3432901e9369..a498f252e693c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -146,10 +146,11 @@ void ento::registerCastSizeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCastSizeChecker(const LangOptions &LO) { +bool ento::shouldRegisterCastSizeChecker(const CheckerManager &mgr) { // PR31226: C++ is more complicated than what this checker currently supports. // There are derived-to-base casts, there are different rules for 0-size // structures, no flexible arrays, etc. // FIXME: Disabled on C++ for now. + const LangOptions &LO = mgr.getLangOpts(); return !LO.CPlusPlus; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index 93665596be298..e674ec43bcd9d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -120,6 +120,6 @@ void ento::registerCastToStructChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCastToStructChecker(const LangOptions &LO) { +bool ento::shouldRegisterCastToStructChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp index 1c3ff3e1b2d9f..85e2b71e53ea1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp @@ -436,6 +436,6 @@ void ento::registerCastValueChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterCastValueChecker(const LangOptions &LO) { +bool ento::shouldRegisterCastValueChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 50b872bd8682f..13836f08a61ef 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -1088,7 +1088,8 @@ void ento::registerObjCDeallocChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterObjCDeallocChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCDeallocChecker(const CheckerManager &mgr) { // These checker only makes sense under MRR. + const LangOptions &LO = mgr.getLangOpts(); return LO.getGC() != LangOptions::GCOnly && !LO.ObjCAutoRefCount; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index 1694c237cda42..175dfcef0df45 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp @@ -138,6 +138,6 @@ void ento::registerObjCMethSigsChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCMethSigsChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCMethSigsChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp index be1a65c474d82..43ed0ffb238d2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp @@ -1,3 +1,15 @@ +//==- CheckPlacementNew.cpp - Check for placement new operation --*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file defines a check for misuse of the default placement new operator. +// +//===----------------------------------------------------------------------===// + #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -117,6 +129,6 @@ void ento::registerPlacementNewChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterPlacementNewChecker(const LangOptions &LO) { +bool ento::shouldRegisterPlacementNewChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index d9ffa562c0aaa..d06c87631bfb5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -1076,7 +1076,7 @@ void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) { +bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) { return true; } @@ -1087,7 +1087,7 @@ bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) { checker->filter.checkName_##name = mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name(const LangOptions &LO) { return true; } + bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(bcmp) REGISTER_CHECKER(bcopy) diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index ec401cfa89859..0d2551f11583e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp @@ -91,6 +91,6 @@ void ento::registerSizeofPointerChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterSizeofPointerChecker(const LangOptions &LO) { +bool ento::shouldRegisterSizeofPointerChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index 7a41a7b6b216e..fd53c04f4bbf0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -136,6 +136,6 @@ void ento::registerChrootChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterChrootChecker(const LangOptions &LO) { +bool ento::shouldRegisterChrootChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp index ce45b5be34c9f..7968aed85e1bc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CloneChecker.cpp @@ -208,6 +208,6 @@ void ento::registerCloneChecker(CheckerManager &Mgr) { .getCheckerStringOption(Checker, "IgnoredFilesPattern"); } -bool ento::shouldRegisterCloneChecker(const LangOptions &LO) { +bool ento::shouldRegisterCloneChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp index 7d8dc8b8a0ab6..73c6517fd0ebf 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp @@ -12,6 +12,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/DeclTemplate.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" @@ -31,47 +32,43 @@ namespace { class ContainerModeling : public Checker { - void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal, - const SVal &Cont) const; - void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal, - const SVal &Cont) const; - void handleAssignment(CheckerContext &C, const SVal &Cont, - const Expr *CE = nullptr, - const SVal &OldCont = UndefinedVal()) const; - void handleAssign(CheckerContext &C, const SVal &Cont) const; - void handleClear(CheckerContext &C, const SVal &Cont) const; - void handlePushBack(CheckerContext &C, const SVal &Cont) const; - void handlePopBack(CheckerContext &C, const SVal &Cont) const; - void handlePushFront(CheckerContext &C, const SVal &Cont) const; - void handlePopFront(CheckerContext &C, const SVal &Cont) const; - void handleInsert(CheckerContext &C, const SVal &Cont, - const SVal &Iter) const; - void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter) const; - void handleErase(CheckerContext &C, const SVal &Cont, const SVal &Iter1, - const SVal &Iter2) const; - void handleEraseAfter(CheckerContext &C, const SVal &Cont, - const SVal &Iter) const; - void handleEraseAfter(CheckerContext &C, const SVal &Cont, const SVal &Iter1, - const SVal &Iter2) const; + void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal, + SVal Cont) const; + void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal, + SVal Cont) const; + void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr, + SVal OldCont = UndefinedVal()) const; + void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const; + void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const; + void handlePushBack(CheckerContext &C, SVal Cont, const Expr *ContE) const; + void handlePopBack(CheckerContext &C, SVal Cont, const Expr *ContE) const; + void handlePushFront(CheckerContext &C, SVal Cont, const Expr *ContE) const; + void handlePopFront(CheckerContext &C, SVal Cont, const Expr *ContE) const; + void handleInsert(CheckerContext &C, SVal Cont, SVal Iter) const; + void handleErase(CheckerContext &C, SVal Cont, SVal Iter) const; + void handleErase(CheckerContext &C, SVal Cont, SVal Iter1, SVal Iter2) const; + void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter) const; + void handleEraseAfter(CheckerContext &C, SVal Cont, SVal Iter1, + SVal Iter2) const; + const NoteTag *getChangeTag(CheckerContext &C, StringRef Text, + const MemRegion *ContReg, + const Expr *ContE) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; public: - ContainerModeling() {} + ContainerModeling() = default; void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; - typedef void (ContainerModeling::*NoItParamFn)(CheckerContext &, - const SVal &) const; - typedef void (ContainerModeling::*OneItParamFn)(CheckerContext &, - const SVal &, - const SVal &) const; - typedef void (ContainerModeling::*TwoItParamFn)(CheckerContext &, - const SVal &, - const SVal &, - const SVal &) const; + using NoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, + const Expr *) const; + using OneItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, + SVal) const; + using TwoItParamFn = void (ContainerModeling::*)(CheckerContext &, SVal, SVal, + SVal) const; CallDescriptionMap NoIterParamFunctions = { {{0, "clear", 0}, @@ -184,7 +181,8 @@ void ContainerModeling::checkPostCall(const CallEvent &Call, if (const auto *InstCall = dyn_cast(&Call)) { const NoItParamFn *Handler0 = NoIterParamFunctions.lookup(Call); if (Handler0) { - (this->**Handler0)(C, InstCall->getCXXThisVal()); + (this->**Handler0)(C, InstCall->getCXXThisVal(), + InstCall->getCXXThisExpr()); return; } @@ -259,7 +257,7 @@ void ContainerModeling::checkDeadSymbols(SymbolReaper &SR, } void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, - const SVal &RetVal, const SVal &Cont) const { + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -281,7 +279,7 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE, } void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, - const SVal &RetVal, const SVal &Cont) const { + SVal RetVal, SVal Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -302,9 +300,8 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE, C.addTransition(State); } -void ContainerModeling::handleAssignment(CheckerContext &C, const SVal &Cont, - const Expr *CE, - const SVal &OldCont) const { +void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont, + const Expr *CE, SVal OldCont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -379,8 +376,8 @@ void ContainerModeling::handleAssignment(CheckerContext &C, const SVal &Cont, C.addTransition(State); } -void ContainerModeling::handleAssign(CheckerContext &C, - const SVal &Cont) const { +void ContainerModeling::handleAssign(CheckerContext &C, SVal Cont, + const Expr *ContE) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -393,7 +390,8 @@ void ContainerModeling::handleAssign(CheckerContext &C, C.addTransition(State); } -void ContainerModeling::handleClear(CheckerContext &C, const SVal &Cont) const { +void ContainerModeling::handleClear(CheckerContext &C, SVal Cont, + const Expr *ContE) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -415,12 +413,14 @@ void ContainerModeling::handleClear(CheckerContext &C, const SVal &Cont) const { } } } + const NoteTag *ChangeTag = + getChangeTag(C, "became empty", ContReg, ContE); State = invalidateAllIteratorPositions(State, ContReg); - C.addTransition(State); + C.addTransition(State, ChangeTag); } -void ContainerModeling::handlePushBack(CheckerContext &C, - const SVal &Cont) const { +void ContainerModeling::handlePushBack(CheckerContext &C, SVal Cont, + const Expr *ContE) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -452,13 +452,15 @@ void ContainerModeling::handlePushBack(CheckerContext &C, nonloc::SymbolVal(EndSym), nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), SymMgr.getType(EndSym)).getAsSymbol(); + const NoteTag *ChangeTag = + getChangeTag(C, "extended to the back by 1 position", ContReg, ContE); State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); + C.addTransition(State, ChangeTag); } - C.addTransition(State); } -void ContainerModeling::handlePopBack(CheckerContext &C, - const SVal &Cont) const { +void ContainerModeling::handlePopBack(CheckerContext &C, SVal Cont, + const Expr *ContE) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -479,6 +481,8 @@ void ContainerModeling::handlePopBack(CheckerContext &C, nonloc::SymbolVal(EndSym), nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), SymMgr.getType(EndSym)).getAsSymbol(); + const NoteTag *ChangeTag = + getChangeTag(C, "shrank from the back by 1 position", ContReg, ContE); // For vector-like and deque-like containers invalidate the last and the // past-end iterator positions. For list-like containers only invalidate // the last position @@ -491,12 +495,12 @@ void ContainerModeling::handlePopBack(CheckerContext &C, } auto newEndSym = BackSym; State = setContainerData(State, ContReg, CData->newEnd(newEndSym)); - C.addTransition(State); + C.addTransition(State, ChangeTag); } } -void ContainerModeling::handlePushFront(CheckerContext &C, - const SVal &Cont) const { +void ContainerModeling::handlePushFront(CheckerContext &C, SVal Cont, + const Expr *ContE) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -522,14 +526,16 @@ void ContainerModeling::handlePushFront(CheckerContext &C, nonloc::SymbolVal(BeginSym), nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), SymMgr.getType(BeginSym)).getAsSymbol(); + const NoteTag *ChangeTag = + getChangeTag(C, "extended to the front by 1 position", ContReg, ContE); State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); - C.addTransition(State); + C.addTransition(State, ChangeTag); } } } -void ContainerModeling::handlePopFront(CheckerContext &C, - const SVal &Cont) const { +void ContainerModeling::handlePopFront(CheckerContext &C, SVal Cont, + const Expr *ContE) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -557,13 +563,15 @@ void ContainerModeling::handlePopFront(CheckerContext &C, nonloc::SymbolVal(BeginSym), nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1))), SymMgr.getType(BeginSym)).getAsSymbol(); + const NoteTag *ChangeTag = + getChangeTag(C, "shrank from the front by 1 position", ContReg, ContE); State = setContainerData(State, ContReg, CData->newBegin(newBeginSym)); - C.addTransition(State); + C.addTransition(State, ChangeTag); } } -void ContainerModeling::handleInsert(CheckerContext &C, const SVal &Cont, - const SVal &Iter) const { +void ContainerModeling::handleInsert(CheckerContext &C, SVal Cont, + SVal Iter) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -593,8 +601,8 @@ void ContainerModeling::handleInsert(CheckerContext &C, const SVal &Cont, } } -void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont, - const SVal &Iter) const { +void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, + SVal Iter) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -627,9 +635,8 @@ void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont, C.addTransition(State); } -void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont, - const SVal &Iter1, - const SVal &Iter2) const { +void ContainerModeling::handleErase(CheckerContext &C, SVal Cont, SVal Iter1, + SVal Iter2) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -664,8 +671,8 @@ void ContainerModeling::handleErase(CheckerContext &C, const SVal &Cont, C.addTransition(State); } -void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont, - const SVal &Iter) const { +void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont, + SVal Iter) const { auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Iter); if (!Pos) @@ -685,9 +692,8 @@ void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont, C.addTransition(State); } -void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont, - const SVal &Iter1, - const SVal &Iter2) const { +void ContainerModeling::handleEraseAfter(CheckerContext &C, SVal Cont, + SVal Iter1, SVal Iter2) const { auto State = C.getState(); const auto *Pos1 = getIteratorPosition(State, Iter1); const auto *Pos2 = getIteratorPosition(State, Iter2); @@ -700,6 +706,33 @@ void ContainerModeling::handleEraseAfter(CheckerContext &C, const SVal &Cont, C.addTransition(State); } +const NoteTag *ContainerModeling::getChangeTag(CheckerContext &C, + StringRef Text, + const MemRegion *ContReg, + const Expr *ContE) const { + StringRef Name; + // First try to get the name of the variable from the region + if (const auto *DR = dyn_cast(ContReg)) { + Name = DR->getDecl()->getName(); + // If the region is not a `DeclRegion` then use the expression instead + } else if (const auto *DRE = + dyn_cast(ContE->IgnoreParenCasts())) { + Name = DRE->getDecl()->getName(); + } + + return C.getNoteTag( + [Text, Name, ContReg](PathSensitiveBugReport &BR) -> std::string { + if (!BR.isInteresting(ContReg)) + return ""; + + SmallString<256> Msg; + llvm::raw_svector_ostream Out(Msg); + Out << "Container " << (!Name.empty() ? ("'" + Name.str() + "' ") : "" ) + << Text; + return std::string(Out.str()); + }); +} + void ContainerModeling::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { auto ContMap = State->get(); @@ -1035,6 +1068,16 @@ void ento::registerContainerModeling(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterContainerModeling(const LangOptions &LO) { +bool ento::shouldRegisterContainerModeling(const CheckerManager &mgr) { + if (!mgr.getLangOpts().CPlusPlus) + return false; + + if (!mgr.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation) { + mgr.getASTContext().getDiagnostics().Report( + diag::err_analyzer_checker_incompatible_analyzer_option) + << "aggressive-binary-operation-simplification" << "false"; + return false; + } + return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp index 8dd3132f07e2b..4216a68831192 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp @@ -196,6 +196,6 @@ void ento::registerConversionChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterConversionChecker(const LangOptions &LO) { +bool ento::shouldRegisterConversionChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 61441889fc649..6bc186aa27558 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -540,6 +540,6 @@ void ento::registerDeadStoresChecker(CheckerManager &Mgr) { AnOpts.getCheckerBooleanOption(Chk, "ShowFixIts"); } -bool ento::shouldRegisterDeadStoresChecker(const LangOptions &LO) { +bool ento::shouldRegisterDeadStoresChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 0cb4be2c7fdc3..e93c1e9b0a6a1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -47,7 +47,7 @@ void ento::registerDominatorsTreeDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDominatorsTreeDumper(const LangOptions &LO) { +bool ento::shouldRegisterDominatorsTreeDumper(const CheckerManager &mgr) { return true; } @@ -73,7 +73,7 @@ void ento::registerPostDominatorsTreeDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterPostDominatorsTreeDumper(const LangOptions &LO) { +bool ento::shouldRegisterPostDominatorsTreeDumper(const CheckerManager &mgr) { return true; } @@ -98,7 +98,7 @@ void ento::registerControlDependencyTreeDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterControlDependencyTreeDumper(const LangOptions &LO) { +bool ento::shouldRegisterControlDependencyTreeDumper(const CheckerManager &mgr) { return true; } @@ -122,7 +122,7 @@ void ento::registerLiveVariablesDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterLiveVariablesDumper(const LangOptions &LO) { +bool ento::shouldRegisterLiveVariablesDumper(const CheckerManager &mgr) { return true; } @@ -145,7 +145,7 @@ void ento::registerLiveStatementsDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterLiveStatementsDumper(const LangOptions &LO) { +bool ento::shouldRegisterLiveStatementsDumper(const CheckerManager &mgr) { return true; } @@ -169,7 +169,7 @@ void ento::registerCFGViewer(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCFGViewer(const LangOptions &LO) { +bool ento::shouldRegisterCFGViewer(const CheckerManager &mgr) { return true; } @@ -199,7 +199,7 @@ void ento::registerCFGDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCFGDumper(const LangOptions &LO) { +bool ento::shouldRegisterCFGDumper(const CheckerManager &mgr) { return true; } @@ -223,7 +223,7 @@ void ento::registerCallGraphViewer(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCallGraphViewer(const LangOptions &LO) { +bool ento::shouldRegisterCallGraphViewer(const CheckerManager &mgr) { return true; } @@ -247,7 +247,7 @@ void ento::registerCallGraphDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCallGraphDumper(const LangOptions &LO) { +bool ento::shouldRegisterCallGraphDumper(const CheckerManager &mgr) { return true; } @@ -291,7 +291,7 @@ void ento::registerConfigDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterConfigDumper(const LangOptions &LO) { +bool ento::shouldRegisterConfigDumper(const CheckerManager &mgr) { return true; } @@ -314,7 +314,7 @@ void ento::registerExplodedGraphViewer(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterExplodedGraphViewer(const LangOptions &LO) { +bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) { return true; } @@ -346,6 +346,6 @@ void ento::registerReportStmts(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterReportStmts(const LangOptions &LO) { +bool ento::shouldRegisterReportStmts(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp index 8d0572723991a..6fed999ffc80c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp @@ -92,7 +92,19 @@ void DebugContainerModeling::analyzerContainerDataField(const CallExpr *CE, if (Field) { State = State->BindExpr(CE, C.getLocationContext(), nonloc::SymbolVal(Field)); - C.addTransition(State); + + // Progpagate interestingness from the container's data (marked + // interesting by an `ExprInspection` debug call to the container + // itself. + const NoteTag *InterestingTag = + C.getNoteTag( + [Cont, Field](PathSensitiveBugReport &BR) -> std::string { + if (BR.isInteresting(Field)) { + BR.markInteresting(Cont); + } + return ""; + }); + C.addTransition(State, InterestingTag); return; } } @@ -133,6 +145,6 @@ void ento::registerDebugContainerModeling(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDebugContainerModeling(const LangOptions &LO) { +bool ento::shouldRegisterDebugContainerModeling(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp index 254e51094b2a7..5833eea56da88 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp @@ -139,6 +139,6 @@ void ento::registerDebugIteratorModeling(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) { +bool ento::shouldRegisterDebugIteratorModeling(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp index 45c1984c5e157..97556ca856a0f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp @@ -148,6 +148,6 @@ void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) { } bool ento::shouldRegisterDeleteWithNonVirtualDtorChecker( - const LangOptions &LO) { + const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 46100cd1dace0..2411f0e2d058f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -304,6 +304,6 @@ void ento::registerDereferenceChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDereferenceChecker(const LangOptions &LO) { +bool ento::shouldRegisterDereferenceChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp index 0c46447e19853..d09f0da3faacd 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -222,7 +222,7 @@ void ento::registerDirectIvarAssignment(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDirectIvarAssignment(const LangOptions &LO) { +bool ento::shouldRegisterDirectIvarAssignment(const CheckerManager &mgr) { return true; } @@ -232,6 +232,6 @@ void ento::registerDirectIvarAssignmentForAnnotatedFunctions( } bool ento::shouldRegisterDirectIvarAssignmentForAnnotatedFunctions( - const LangOptions &LO) { + const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 8798bde88dcd6..2b3164ba4a2c8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -101,6 +101,6 @@ void ento::registerDivZeroChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDivZeroChecker(const LangOptions &LO) { +bool ento::shouldRegisterDivZeroChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp index 8cc38f9735f33..dbc930d7d37b7 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypeChecker.cpp @@ -203,6 +203,6 @@ void ento::registerDynamicTypeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDynamicTypeChecker(const LangOptions &LO) { +bool ento::shouldRegisterDynamicTypeChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index cce3449b8873f..71681594a0a14 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -981,7 +981,7 @@ void ento::registerObjCGenericsChecker(CheckerManager &mgr) { checker->CheckGenerics = true; } -bool ento::shouldRegisterObjCGenericsChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCGenericsChecker(const CheckerManager &mgr) { return true; } @@ -989,6 +989,6 @@ void ento::registerDynamicTypePropagation(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterDynamicTypePropagation(const LangOptions &LO) { +bool ento::shouldRegisterDynamicTypePropagation(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp index 481a5685a71f6..0e94b915a468f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -142,6 +142,6 @@ void ento::registerEnumCastOutOfRangeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterEnumCastOutOfRangeChecker(const LangOptions &LO) { +bool ento::shouldRegisterEnumCastOutOfRangeChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 10b27831d89f8..4225d890c47a5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -52,9 +52,12 @@ class ExprInspectionChecker : public Checker ExprVal = None) const; ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, - ExplodedNode *N) const; + ExplodedNode *N, + Optional ExprVal = None) const; public: bool evalCall(const CallEvent &Call, CheckerContext &C) const; @@ -144,22 +147,28 @@ static const char *getArgumentValueString(const CallExpr *CE, } ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg, - CheckerContext &C) const { + CheckerContext &C, + Optional ExprVal) const { ExplodedNode *N = C.generateNonFatalErrorNode(); - reportBug(Msg, C.getBugReporter(), N); + reportBug(Msg, C.getBugReporter(), N, ExprVal); return N; } ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg, BugReporter &BR, - ExplodedNode *N) const { + ExplodedNode *N, + Optional ExprVal) const { if (!N) return nullptr; if (!BT) BT.reset(new BugType(this, "Checking analyzer assumptions", "debug")); - BR.emitReport(std::make_unique(*BT, Msg, N)); + auto R = std::make_unique(*BT, Msg, N); + if (ExprVal) { + R->markInteresting(*ExprVal); + } + BR.emitReport(std::move(R)); return N; } @@ -406,7 +415,8 @@ void ExprInspectionChecker::analyzerExpress(const CallExpr *CE, return; } - SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol(); + SVal ArgVal = C.getSVal(CE->getArg(0)); + SymbolRef Sym = ArgVal.getAsSymbol(); if (!Sym) { reportBug("Not a symbol", C); return; @@ -419,7 +429,7 @@ void ExprInspectionChecker::analyzerExpress(const CallExpr *CE, return; } - reportBug(*Str, C); + reportBug(*Str, C, ArgVal); } void ExprInspectionChecker::analyzerIsTainted(const CallExpr *CE, @@ -437,6 +447,6 @@ void ento::registerExprInspectionChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterExprInspectionChecker(const LangOptions &LO) { +bool ento::shouldRegisterExprInspectionChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp index b315a84522859..6275e49e51ae4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -66,6 +66,6 @@ void ento::registerFixedAddressChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterFixedAddressChecker(const LangOptions &LO) { +bool ento::shouldRegisterFixedAddressChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp index dee2212cd5d83..78c51f3eab010 100644 --- a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -565,7 +565,7 @@ void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterFuchsiaHandleChecker(const LangOptions &LO) { +bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp index 76fa56406443a..63fbe75fd4983 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp @@ -225,6 +225,6 @@ void ento::registerGCDAntipattern(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterGCDAntipattern(const LangOptions &LO) { +bool ento::shouldRegisterGCDAntipattern(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp index f4308f510f0ba..8d9afbe88aa84 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp @@ -291,8 +291,9 @@ void ento::registerGTestChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterGTestChecker(const LangOptions &LO) { +bool ento::shouldRegisterGTestChecker(const CheckerManager &mgr) { // gtest is a C++ API so there is no sense running the checker // if not compiling for C++. + const LangOptions &LO = mgr.getLangOpts(); return LO.CPlusPlus; } diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 3dca242f15c3d..1f3e749892293 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -948,6 +948,6 @@ void ento::registerGenericTaintChecker(CheckerManager &Mgr) { Checker->parseConfiguration(Mgr, Option, std::move(Config.getValue())); } -bool ento::shouldRegisterGenericTaintChecker(const LangOptions &LO) { +bool ento::shouldRegisterGenericTaintChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp index cc2cfb7742270..1cf81b54e77d3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp @@ -351,6 +351,8 @@ static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, case Stmt::CallExprClass: case Stmt::ArraySubscriptExprClass: case Stmt::OMPArraySectionExprClass: + case Stmt::OMPArrayShapingExprClass: + case Stmt::OMPIteratorExprClass: case Stmt::ImplicitCastExprClass: case Stmt::ParenExprClass: case Stmt::BreakStmtClass: @@ -513,6 +515,6 @@ void ento::registerIdenticalExprChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterIdenticalExprChecker(const LangOptions &LO) { +bool ento::shouldRegisterIdenticalExprChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp index dd89c53478e8a..65e52e139ee41 100644 --- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp @@ -307,6 +307,6 @@ void ento::registerInnerPointerChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterInnerPointerChecker(const LangOptions &LO) { +bool ento::shouldRegisterInnerPointerChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp index d1a9a7df071d7..c6cd11b09a4ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp @@ -90,6 +90,6 @@ void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterInvalidatedIteratorChecker(const LangOptions &LO) { +bool ento::shouldRegisterInvalidatedIteratorChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp index 9a813b0a1a456..2850c6d393226 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -717,6 +717,6 @@ void ento::registerIteratorModeling(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) { +bool ento::shouldRegisterIteratorModeling(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp index f9b493bf9bb03..6e86ef0c552a9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp @@ -221,7 +221,12 @@ void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val, ExplodedNode *ErrNode) const { auto R = std::make_unique(*OutOfRangeBugType, Message, ErrNode); + + const auto *Pos = getIteratorPosition(C.getState(), Val); + assert(Pos && "Iterator without known position cannot be out-of-range."); + R->markInteresting(Val); + R->markInteresting(Pos->getContainer()); C.emitReport(std::move(R)); } @@ -304,6 +309,6 @@ void ento::registerIteratorRangeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterIteratorRangeChecker(const LangOptions &LO) { +bool ento::shouldRegisterIteratorRangeChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp index 0d64fbd6f62ec..3e6756efe0e69 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -739,7 +739,7 @@ void ento::registerIvarInvalidationModeling(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterIvarInvalidationModeling(const LangOptions &LO) { +bool ento::shouldRegisterIvarInvalidationModeling(const CheckerManager &mgr) { return true; } @@ -751,7 +751,7 @@ bool ento::shouldRegisterIvarInvalidationModeling(const LangOptions &LO) { checker->Filter.checkName_##name = mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name(const LangOptions &LO) { return true; } + bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(InstanceVariableInvalidation) REGISTER_CHECKER(MissingInvalidationMethod) diff --git a/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 7522fdd0a99b3..1f3d8844d330e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp @@ -314,6 +314,6 @@ void ento::registerLLVMConventionsChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterLLVMConventionsChecker(const LangOptions &LO) { +bool ento::shouldRegisterLLVMConventionsChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp index 79de1844e7452..252377f24bd7b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -1403,7 +1403,7 @@ void ento::registerNonLocalizedStringChecker(CheckerManager &mgr) { checker, "AggressiveReport"); } -bool ento::shouldRegisterNonLocalizedStringChecker(const LangOptions &LO) { +bool ento::shouldRegisterNonLocalizedStringChecker(const CheckerManager &mgr) { return true; } @@ -1412,7 +1412,7 @@ void ento::registerEmptyLocalizationContextChecker(CheckerManager &mgr) { } bool ento::shouldRegisterEmptyLocalizationContextChecker( - const LangOptions &LO) { + const CheckerManager &mgr) { return true; } @@ -1420,6 +1420,6 @@ void ento::registerPluralMisuseChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterPluralMisuseChecker(const LangOptions &LO) { +bool ento::shouldRegisterPluralMisuseChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp index d7555b78ac40b..837213875a60c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp @@ -293,6 +293,6 @@ void ento::registerMIGChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterMIGChecker(const LangOptions &LO) { +bool ento::shouldRegisterMIGChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp index cde5ee3cbac39..7ac7a38dacf33 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp @@ -190,6 +190,6 @@ void clang::ento::registerMPIChecker(CheckerManager &MGR) { MGR.registerChecker(); } -bool clang::ento::shouldRegisterMPIChecker(const LangOptions &LO) { +bool clang::ento::shouldRegisterMPIChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index e064ca6bd88f6..43f7dcd14b014 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -667,6 +667,6 @@ void ento::registerMacOSKeychainAPIChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterMacOSKeychainAPIChecker(const LangOptions &LO) { +bool ento::shouldRegisterMacOSKeychainAPIChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index 410721d8b6ff6..04e7f8dec8d77 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -176,6 +176,6 @@ void ento::registerMacOSXAPIChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterMacOSXAPIChecker(const LangOptions &LO) { +bool ento::shouldRegisterMacOSXAPIChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 23b4abc670798..52786bcaf072f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -58,19 +58,23 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include +#include #include using namespace clang; using namespace ento; +using namespace std::placeholders; //===----------------------------------------------------------------------===// // The types of allocation we're modeling. This is used to check whether a @@ -92,8 +96,6 @@ enum AllocationFamily { AF_InnerBuffer }; -struct MemFunctionInfoTy; - } // end of anonymous namespace /// Print names of allocators and deallocators. @@ -262,47 +264,6 @@ struct ReallocPair { REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair) -//===----------------------------------------------------------------------===// -// Kinds of memory operations, information about resource managing functions. -//===----------------------------------------------------------------------===// - -namespace { - -struct MemFunctionInfoTy { - /// The value of the MallocChecker:Optimistic is stored in this variable. - /// - /// In pessimistic mode, the checker assumes that it does not know which - /// functions might free the memory. - /// In optimistic mode, the checker assumes that all user-defined functions - /// which might free a pointer are annotated. - DefaultBool ShouldIncludeOwnershipAnnotatedFunctions; - - CallDescription CD_alloca{{"alloca"}, 1}, CD_win_alloca{{"_alloca"}, 1}, - CD_malloc{{"malloc"}, 1}, CD_BSD_malloc{{"malloc"}, 3}, - CD_free{{"free"}, 1}, CD_realloc{{"realloc"}, 2}, - CD_calloc{{"calloc"}, 2}, CD_valloc{{"valloc"}, 1}, - CD_reallocf{{"reallocf"}, 2}, CD_strndup{{"strndup"}, 2}, - CD_strdup{{"strdup"}, 1}, CD_win_strdup{{"_strdup"}, 1}, - CD_kmalloc{{"kmalloc"}, 2}, CD_if_nameindex{{"if_nameindex"}, 1}, - CD_if_freenameindex{{"if_freenameindex"}, 1}, CD_wcsdup{{"wcsdup"}, 1}, - CD_win_wcsdup{{"_wcsdup"}, 1}, CD_kfree{{"kfree"}, 2}, - CD_g_malloc{{"g_malloc"}, 1}, CD_g_malloc0{{"g_malloc0"}, 1}, - CD_g_realloc{{"g_realloc"}, 2}, CD_g_try_malloc{{"g_try_malloc"}, 1}, - CD_g_try_malloc0{{"g_try_malloc0"}, 1}, - CD_g_try_realloc{{"g_try_realloc"}, 2}, CD_g_free{{"g_free"}, 1}, - CD_g_memdup{{"g_memdup"}, 2}, CD_g_malloc_n{{"g_malloc_n"}, 2}, - CD_g_malloc0_n{{"g_malloc0_n"}, 2}, CD_g_realloc_n{{"g_realloc_n"}, 3}, - CD_g_try_malloc_n{{"g_try_malloc_n"}, 2}, - CD_g_try_malloc0_n{{"g_try_malloc0_n"}, 2}, - CD_g_try_realloc_n{{"g_try_realloc_n"}, 3}; - - bool isMemFunction(const CallEvent &Call) const; - bool isCMemFunction(const CallEvent &Call) const; - bool isCMemFreeFunction(const CallEvent &Call) const; - bool isCMemAllocFunction(const CallEvent &Call) const; -}; -} // end of anonymous namespace - /// Tells if the callee is one of the builtin new/delete operators, including /// placement operators and other standard overloads. static bool isStandardNewDelete(const FunctionDecl *FD); @@ -326,7 +287,11 @@ class MallocChecker check::PreStmt, check::PostStmt, check::PostObjCMessage, check::Location, eval::Assume> { public: - MemFunctionInfoTy MemFunctionInfo; + /// In pessimistic mode, the checker assumes that it does not know which + /// functions might free the memory. + /// In optimistic mode, the checker assumes that all user-defined functions + /// which might free a pointer are annotated. + DefaultBool ShouldIncludeOwnershipAnnotatedFunctions; /// Many checkers are essentially built into this one, so enabling them will /// make MallocChecker perform additional modeling and reporting. @@ -386,9 +351,91 @@ class MallocChecker mutable std::unique_ptr BT_OffsetFree[CK_NumCheckKinds]; mutable std::unique_ptr BT_UseZerroAllocated[CK_NumCheckKinds]; +#define CHECK_FN(NAME) \ + void NAME(CheckerContext &C, const CallExpr *CE, ProgramStateRef State) const; + + CHECK_FN(checkFree) + CHECK_FN(checkIfNameIndex) + CHECK_FN(checkBasicAlloc) + CHECK_FN(checkKernelMalloc) + CHECK_FN(checkCalloc) + CHECK_FN(checkAlloca) + CHECK_FN(checkStrdup) + CHECK_FN(checkIfFreeNameIndex) + CHECK_FN(checkCXXNewOrCXXDelete) + CHECK_FN(checkGMalloc0) + CHECK_FN(checkGMemdup) + CHECK_FN(checkGMallocN) + CHECK_FN(checkGMallocN0) + CHECK_FN(checkReallocN) + CHECK_FN(checkOwnershipAttr) + + void checkRealloc(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State, bool ShouldFreeOnFail) const; + + using CheckFn = + std::function; + + const CallDescriptionMap FreeingMemFnMap{ + {{"free", 1}, &MallocChecker::checkFree}, + {{"if_freenameindex", 1}, &MallocChecker::checkIfFreeNameIndex}, + {{"kfree", 1}, &MallocChecker::checkFree}, + {{"g_free", 1}, &MallocChecker::checkFree}, + }; + + bool isFreeingCall(const CallEvent &Call) const; + + CallDescriptionMap AllocatingMemFnMap{ + {{"alloca", 1}, &MallocChecker::checkAlloca}, + {{"_alloca", 1}, &MallocChecker::checkAlloca}, + {{"malloc", 1}, &MallocChecker::checkBasicAlloc}, + {{"malloc", 3}, &MallocChecker::checkKernelMalloc}, + {{"calloc", 2}, &MallocChecker::checkCalloc}, + {{"valloc", 1}, &MallocChecker::checkBasicAlloc}, + {{CDF_MaybeBuiltin, "strndup", 2}, &MallocChecker::checkStrdup}, + {{CDF_MaybeBuiltin, "strdup", 1}, &MallocChecker::checkStrdup}, + {{"_strdup", 1}, &MallocChecker::checkStrdup}, + {{"kmalloc", 2}, &MallocChecker::checkKernelMalloc}, + {{"if_nameindex", 1}, &MallocChecker::checkIfNameIndex}, + {{CDF_MaybeBuiltin, "wcsdup", 1}, &MallocChecker::checkStrdup}, + {{CDF_MaybeBuiltin, "_wcsdup", 1}, &MallocChecker::checkStrdup}, + {{"g_malloc", 1}, &MallocChecker::checkBasicAlloc}, + {{"g_malloc0", 1}, &MallocChecker::checkGMalloc0}, + {{"g_try_malloc", 1}, &MallocChecker::checkBasicAlloc}, + {{"g_try_malloc0", 1}, &MallocChecker::checkGMalloc0}, + {{"g_memdup", 2}, &MallocChecker::checkGMemdup}, + {{"g_malloc_n", 2}, &MallocChecker::checkGMallocN}, + {{"g_malloc0_n", 2}, &MallocChecker::checkGMallocN0}, + {{"g_try_malloc_n", 2}, &MallocChecker::checkGMallocN}, + {{"g_try_malloc0_n", 2}, &MallocChecker::checkGMallocN0}, + }; + + CallDescriptionMap ReallocatingMemFnMap{ + {{"realloc", 2}, + std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)}, + {{"reallocf", 2}, + std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, true)}, + {{"g_realloc", 2}, + std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)}, + {{"g_try_realloc", 2}, + std::bind(&MallocChecker::checkRealloc, _1, _2, _3, _4, false)}, + {{"g_realloc_n", 3}, &MallocChecker::checkReallocN}, + {{"g_try_realloc_n", 3}, &MallocChecker::checkReallocN}, + }; + + bool isMemCall(const CallEvent &Call) const; + // TODO: Remove mutable by moving the initializtaion to the registry function. mutable Optional KernelZeroFlagVal; + using KernelZeroSizePtrValueTy = Optional; + /// Store the value of macro called `ZERO_SIZE_PTR`. + /// The value is initialized at first use, before first use the outer + /// Optional is empty, afterwards it contains another Optional that indicates + /// if the macro value could be determined, and if yes the value itself. + mutable Optional KernelZeroSizePtrValue; + /// Process C++ operator new()'s allocation, which is the part of C++ /// new-expression that goes before the constructor. void processNewAllocation(const CXXNewExpr *NE, CheckerContext &C, @@ -658,6 +705,10 @@ class MallocChecker CheckerContext &C); void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; + + /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`. + bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, + SVal ArgVal) const; }; //===----------------------------------------------------------------------===// @@ -810,28 +861,31 @@ class StopTrackingCallback final : public SymbolVisitor { }; } // end anonymous namespace -//===----------------------------------------------------------------------===// -// Methods of MemFunctionInfoTy. -//===----------------------------------------------------------------------===// +static bool isStandardNewDelete(const FunctionDecl *FD) { + if (!FD) + return false; -bool MemFunctionInfoTy::isMemFunction(const CallEvent &Call) const { - return isCMemFunction(Call) || isStandardNewDelete(Call); -} + OverloadedOperatorKind Kind = FD->getOverloadedOperator(); + if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete && + Kind != OO_Array_Delete) + return false; -bool MemFunctionInfoTy::isCMemFunction(const CallEvent &Call) const { - return isCMemFreeFunction(Call) || isCMemAllocFunction(Call); + // This is standard if and only if it's not defined in a user file. + SourceLocation L = FD->getLocation(); + // If the header for operator delete is not included, it's still defined + // in an invalid source location. Check to make sure we don't crash. + return !L.isValid() || + FD->getASTContext().getSourceManager().isInSystemHeader(L); } -bool MemFunctionInfoTy::isCMemFreeFunction(const CallEvent &Call) const { - if (Call.isCalled(CD_free, CD_realloc, CD_reallocf, CD_g_free, CD_kfree)) - return true; +//===----------------------------------------------------------------------===// +// Methods of MallocChecker and MallocBugVisitor. +//===----------------------------------------------------------------------===// - if (Call.isCalled(CD_if_freenameindex)) +bool MallocChecker::isFreeingCall(const CallEvent &Call) const { + if (FreeingMemFnMap.lookup(Call) || ReallocatingMemFnMap.lookup(Call)) return true; - if (!ShouldIncludeOwnershipAnnotatedFunctions) - return false; - const auto *Func = dyn_cast(Call.getDecl()); if (Func && Func->hasAttrs()) { for (const auto *I : Func->specific_attrs()) { @@ -843,60 +897,21 @@ bool MemFunctionInfoTy::isCMemFreeFunction(const CallEvent &Call) const { return false; } -bool MemFunctionInfoTy::isCMemAllocFunction(const CallEvent &Call) const { - if (Call.isCalled(CD_malloc, CD_realloc, CD_reallocf, CD_calloc, CD_valloc, - CD_strdup, CD_win_strdup, CD_strndup, CD_wcsdup, - CD_win_wcsdup, CD_kmalloc, CD_g_malloc, CD_g_malloc0, - CD_g_realloc, CD_g_try_malloc, CD_g_try_malloc0, - CD_g_try_realloc, CD_g_memdup, CD_g_malloc_n, - CD_g_malloc0_n, CD_g_realloc_n, CD_g_try_malloc_n, - CD_g_try_malloc0_n, CD_g_try_realloc_n)) - return true; - - if (Call.isCalled(CD_if_nameindex)) - return true; - - if (Call.isCalled(CD_alloca, CD_win_alloca)) +bool MallocChecker::isMemCall(const CallEvent &Call) const { + if (FreeingMemFnMap.lookup(Call) || AllocatingMemFnMap.lookup(Call) || + ReallocatingMemFnMap.lookup(Call)) return true; if (!ShouldIncludeOwnershipAnnotatedFunctions) return false; const auto *Func = dyn_cast(Call.getDecl()); - if (Func && Func->hasAttrs()) { - for (const auto *I : Func->specific_attrs()) { - OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind(); - if (OwnKind == OwnershipAttr::Returns) - return true; - } - } - - return false; -} - -static bool isStandardNewDelete(const FunctionDecl *FD) { - if (!FD) - return false; - - OverloadedOperatorKind Kind = FD->getOverloadedOperator(); - if (Kind != OO_New && Kind != OO_Array_New && Kind != OO_Delete && - Kind != OO_Array_Delete) - return false; - - // This is standard if and only if it's not defined in a user file. - SourceLocation L = FD->getLocation(); - // If the header for operator delete is not included, it's still defined - // in an invalid source location. Check to make sure we don't crash. - return !L.isValid() || - FD->getASTContext().getSourceManager().isInSystemHeader(L); + return Func && Func->hasAttr(); } -//===----------------------------------------------------------------------===// -// Methods of MallocChecker and MallocBugVisitor. -//===----------------------------------------------------------------------===// - -llvm::Optional MallocChecker::performKernelMalloc( - const CallExpr *CE, CheckerContext &C, const ProgramStateRef &State) const { +llvm::Optional +MallocChecker::performKernelMalloc(const CallExpr *CE, CheckerContext &C, + const ProgramStateRef &State) const { // 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels: // // void *malloc(unsigned long size, struct malloc_type *mtp, int flags); @@ -984,173 +999,169 @@ SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks, return TotalSize; } -void MallocChecker::checkPostCall(const CallEvent &Call, - CheckerContext &C) const { - if (C.wasInlined) - return; +void MallocChecker::checkBasicAlloc(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Malloc); + State = ProcessZeroAllocCheck(C, CE, 0, State); + C.addTransition(State); +} - const auto *CE = dyn_cast_or_null(Call.getOriginExpr()); - if (!CE) - return; +void MallocChecker::checkKernelMalloc(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + llvm::Optional MaybeState = + performKernelMalloc(CE, C, State); + if (MaybeState.hasValue()) + State = MaybeState.getValue(); + else + State = + MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Malloc); + C.addTransition(State); +} - const FunctionDecl *FD = C.getCalleeDecl(CE); - if (!FD) +void MallocChecker::checkRealloc(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State, + bool ShouldFreeOnFail) const { + State = ReallocMemAux(C, CE, ShouldFreeOnFail, State, AF_Malloc); + State = ProcessZeroAllocCheck(C, CE, 1, State); + C.addTransition(State); +} + +void MallocChecker::checkCalloc(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + State = CallocMem(C, CE, State); + State = ProcessZeroAllocCheck(C, CE, 0, State); + State = ProcessZeroAllocCheck(C, CE, 1, State); + C.addTransition(State); +} + +void MallocChecker::checkFree(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + bool IsKnownToBeAllocatedMemory = false; + if (suppressDeallocationsInSuspiciousContexts(CE, C)) return; + State = + FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, AF_Malloc); + C.addTransition(State); +} - ProgramStateRef State = C.getState(); +void MallocChecker::checkAlloca(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Alloca); + State = ProcessZeroAllocCheck(C, CE, 0, State); + C.addTransition(State); +} + +void MallocChecker::checkStrdup(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + State = MallocUpdateRefState(C, CE, State, AF_Malloc); + + C.addTransition(State); +} + +void MallocChecker::checkIfNameIndex(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + // Should we model this differently? We can allocate a fixed number of + // elements with zeros in the last one. + State = + MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State, AF_IfNameIndex); + + C.addTransition(State); +} + +void MallocChecker::checkIfFreeNameIndex(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { bool IsKnownToBeAllocatedMemory = false; + State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, + AF_IfNameIndex); + C.addTransition(State); +} - if (FD->getKind() == Decl::Function) { - if (Call.isCalled(MemFunctionInfo.CD_malloc, MemFunctionInfo.CD_BSD_malloc, - MemFunctionInfo.CD_g_malloc, - MemFunctionInfo.CD_g_try_malloc)) { - switch (CE->getNumArgs()) { - default: - return; - case 1: - State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, - AF_Malloc); - State = ProcessZeroAllocCheck(C, CE, 0, State); - break; - case 2: - llvm_unreachable("There shouldn't be a 2-argument malloc!"); - break; - case 3: - llvm::Optional MaybeState = - performKernelMalloc(CE, C, State); - if (MaybeState.hasValue()) - State = MaybeState.getValue(); - else - State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, - AF_Malloc); - break; - } - } else if (Call.isCalled(MemFunctionInfo.CD_kmalloc)) { - if (CE->getNumArgs() < 1) - return; - llvm::Optional MaybeState = - performKernelMalloc(CE, C, State); - if (MaybeState.hasValue()) - State = MaybeState.getValue(); - else - State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, - AF_Malloc); - } else if (Call.isCalled(MemFunctionInfo.CD_valloc)) { - if (CE->getNumArgs() < 1) - return; - State = - MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Malloc); - State = ProcessZeroAllocCheck(C, CE, 0, State); - } else if (Call.isCalled(MemFunctionInfo.CD_realloc, - MemFunctionInfo.CD_g_realloc, - MemFunctionInfo.CD_g_try_realloc)) { - State = - ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State, AF_Malloc); - State = ProcessZeroAllocCheck(C, CE, 1, State); - } else if (Call.isCalled(MemFunctionInfo.CD_reallocf)) { - State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ true, State, AF_Malloc); - State = ProcessZeroAllocCheck(C, CE, 1, State); - } else if (Call.isCalled(MemFunctionInfo.CD_calloc)) { - State = CallocMem(C, CE, State); - State = ProcessZeroAllocCheck(C, CE, 0, State); - State = ProcessZeroAllocCheck(C, CE, 1, State); - } else if (Call.isCalled(MemFunctionInfo.CD_free, MemFunctionInfo.CD_g_free, - MemFunctionInfo.CD_kfree)) { - if (suppressDeallocationsInSuspiciousContexts(CE, C)) - return; +void MallocChecker::checkCXXNewOrCXXDelete(CheckerContext &C, + const CallExpr *CE, + ProgramStateRef State) const { + bool IsKnownToBeAllocatedMemory = false; - State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, - AF_Malloc); - } else if (Call.isCalled( - MemFunctionInfo.CD_strdup, MemFunctionInfo.CD_win_strdup, - MemFunctionInfo.CD_wcsdup, MemFunctionInfo.CD_win_wcsdup)) { - State = MallocUpdateRefState(C, CE, State, AF_Malloc); - } else if (Call.isCalled(MemFunctionInfo.CD_strndup)) { - State = MallocUpdateRefState(C, CE, State, AF_Malloc); - } else if (Call.isCalled(MemFunctionInfo.CD_alloca, - MemFunctionInfo.CD_win_alloca)) { - if (CE->getNumArgs() < 1) - return; - State = - MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Alloca); - State = ProcessZeroAllocCheck(C, CE, 0, State); - } else if (isStandardNewDelete(FD)) { - // Process direct calls to operator new/new[]/delete/delete[] functions - // as distinct from new/new[]/delete/delete[] expressions that are - // processed by the checkPostStmt callbacks for CXXNewExpr and - // CXXDeleteExpr. - switch (FD->getOverloadedOperator()) { - case OO_New: - State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, - AF_CXXNew); - State = ProcessZeroAllocCheck(C, CE, 0, State); - break; - case OO_Array_New: - State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, - AF_CXXNewArray); - State = ProcessZeroAllocCheck(C, CE, 0, State); - break; - case OO_Delete: - State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, - AF_CXXNew); - break; - case OO_Array_Delete: - State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, - AF_CXXNewArray); - break; - default: - llvm_unreachable("not a new/delete operator"); - } - } else if (Call.isCalled(MemFunctionInfo.CD_if_nameindex)) { - // Should we model this differently? We can allocate a fixed number of - // elements with zeros in the last one. - State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State, - AF_IfNameIndex); - } else if (Call.isCalled(MemFunctionInfo.CD_if_freenameindex)) { - State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, - AF_IfNameIndex); - } else if (Call.isCalled(MemFunctionInfo.CD_g_malloc0, - MemFunctionInfo.CD_g_try_malloc0)) { - if (CE->getNumArgs() < 1) - return; - SValBuilder &svalBuilder = C.getSValBuilder(); - SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); - State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State, AF_Malloc); - State = ProcessZeroAllocCheck(C, CE, 0, State); - } else if (Call.isCalled(MemFunctionInfo.CD_g_memdup)) { - if (CE->getNumArgs() < 2) - return; - State = - MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State, AF_Malloc); - State = ProcessZeroAllocCheck(C, CE, 1, State); - } else if (Call.isCalled(MemFunctionInfo.CD_g_malloc_n, - MemFunctionInfo.CD_g_try_malloc_n, - MemFunctionInfo.CD_g_malloc0_n, - MemFunctionInfo.CD_g_try_malloc0_n)) { - if (CE->getNumArgs() < 2) - return; - SVal Init = UndefinedVal(); - if (Call.isCalled(MemFunctionInfo.CD_g_malloc0_n, - MemFunctionInfo.CD_g_try_malloc0_n)) { - SValBuilder &SB = C.getSValBuilder(); - Init = SB.makeZeroVal(SB.getContext().CharTy); - } - SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1)); - State = MallocMemAux(C, CE, TotalSize, Init, State, AF_Malloc); - State = ProcessZeroAllocCheck(C, CE, 0, State); - State = ProcessZeroAllocCheck(C, CE, 1, State); - } else if (Call.isCalled(MemFunctionInfo.CD_g_realloc_n, - MemFunctionInfo.CD_g_try_realloc_n)) { - if (CE->getNumArgs() < 3) - return; - State = ReallocMemAux(C, CE, /*ShouldFreeOnFail*/ false, State, AF_Malloc, - /*SuffixWithN*/ true); - State = ProcessZeroAllocCheck(C, CE, 1, State); - State = ProcessZeroAllocCheck(C, CE, 2, State); - } + const FunctionDecl *FD = C.getCalleeDecl(CE); + // Process direct calls to operator new/new[]/delete/delete[] functions + // as distinct from new/new[]/delete/delete[] expressions that are + // processed by the checkPostStmt callbacks for CXXNewExpr and + // CXXDeleteExpr. + switch (FD->getOverloadedOperator()) { + case OO_New: + State = + MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_CXXNew); + State = ProcessZeroAllocCheck(C, CE, 0, State); + break; + case OO_Array_New: + State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, + AF_CXXNewArray); + State = ProcessZeroAllocCheck(C, CE, 0, State); + break; + case OO_Delete: + State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, + AF_CXXNew); + break; + case OO_Array_Delete: + State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory, + AF_CXXNewArray); + break; + default: + llvm_unreachable("not a new/delete operator"); } - if (MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions || + C.addTransition(State); +} + +void MallocChecker::checkGMalloc0(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + SValBuilder &svalBuilder = C.getSValBuilder(); + SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); + State = MallocMemAux(C, CE, CE->getArg(0), zeroVal, State, AF_Malloc); + State = ProcessZeroAllocCheck(C, CE, 0, State); + C.addTransition(State); +} + +void MallocChecker::checkGMemdup(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + State = MallocMemAux(C, CE, CE->getArg(1), UndefinedVal(), State, AF_Malloc); + State = ProcessZeroAllocCheck(C, CE, 1, State); + C.addTransition(State); +} + +void MallocChecker::checkGMallocN(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + SVal Init = UndefinedVal(); + SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1)); + State = MallocMemAux(C, CE, TotalSize, Init, State, AF_Malloc); + State = ProcessZeroAllocCheck(C, CE, 0, State); + State = ProcessZeroAllocCheck(C, CE, 1, State); + C.addTransition(State); +} + +void MallocChecker::checkGMallocN0(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + SValBuilder &SB = C.getSValBuilder(); + SVal Init = SB.makeZeroVal(SB.getContext().CharTy); + SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1)); + State = MallocMemAux(C, CE, TotalSize, Init, State, AF_Malloc); + State = ProcessZeroAllocCheck(C, CE, 0, State); + State = ProcessZeroAllocCheck(C, CE, 1, State); + C.addTransition(State); +} + +void MallocChecker::checkReallocN(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + State = ReallocMemAux(C, CE, /*ShouldFreeOnFail=*/false, State, AF_Malloc, + /*SuffixWithN=*/true); + State = ProcessZeroAllocCheck(C, CE, 1, State); + State = ProcessZeroAllocCheck(C, CE, 2, State); + C.addTransition(State); +} + +void MallocChecker::checkOwnershipAttr(CheckerContext &C, const CallExpr *CE, + ProgramStateRef State) const { + const FunctionDecl *FD = C.getCalleeDecl(CE); + if (ShouldIncludeOwnershipAnnotatedFunctions || ChecksEnabled[CK_MismatchedDeallocatorChecker]) { // Check all the attributes, if there are any. // There can be multiple of these attributes. @@ -1170,6 +1181,44 @@ void MallocChecker::checkPostCall(const CallEvent &Call, C.addTransition(State); } +void MallocChecker::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { + if (C.wasInlined) + return; + + const auto *CE = dyn_cast_or_null(Call.getOriginExpr()); + if (!CE) + return; + + const FunctionDecl *FD = C.getCalleeDecl(CE); + if (!FD) + return; + + ProgramStateRef State = C.getState(); + + if (const CheckFn *Callback = FreeingMemFnMap.lookup(Call)) { + (*Callback)(this, C, CE, State); + return; + } + + if (const CheckFn *Callback = AllocatingMemFnMap.lookup(Call)) { + (*Callback)(this, C, CE, State); + return; + } + + if (const CheckFn *Callback = ReallocatingMemFnMap.lookup(Call)) { + (*Callback)(this, C, CE, State); + return; + } + + if (isStandardNewDelete(Call)) { + checkCXXNewOrCXXDelete(C, CE, State); + return; + } + + checkOwnershipAttr(C, CE, State); +} + // Performs a 0-sized allocations check. ProgramStateRef MallocChecker::ProcessZeroAllocCheck( CheckerContext &C, const Expr *E, const unsigned IndexOfSizeArg, @@ -1436,8 +1485,7 @@ MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, if (!State) return nullptr; - if (Att->getModule()->getName() != - MemFunctionInfo.CD_malloc.getFunctionName()) + if (Att->getModule()->getName() != "malloc") return nullptr; OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); @@ -1533,8 +1581,7 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, if (!State) return nullptr; - if (Att->getModule()->getName() != - MemFunctionInfo.CD_malloc.getFunctionName()) + if (Att->getModule()->getName() != "malloc") return nullptr; bool IsKnownToBeAllocated = false; @@ -1677,7 +1724,13 @@ ProgramStateRef MallocChecker::FreeMemAux( // Nonlocs can't be freed, of course. // Non-region locations (labels and fixed addresses) also shouldn't be freed. if (!R) { - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family); + // Exception: + // If the macro ZERO_SIZE_PTR is defined, this could be a kernel source + // code. In that case, the ZERO_SIZE_PTR defines a special value used for a + // zero-sized memory block which is allowed to be freed, despite not being a + // null pointer. + if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal)) + ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family); return nullptr; } @@ -2579,8 +2632,7 @@ void MallocChecker::checkPreCall(const CallEvent &Call, if (!FD) return; - if (ChecksEnabled[CK_MallocChecker] && - (MemFunctionInfo.isCMemFreeFunction(Call))) + if (ChecksEnabled[CK_MallocChecker] && isFreeingCall(Call)) return; } @@ -2879,7 +2931,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // If it's one of the allocation functions we can reason about, we model // its behavior explicitly. - if (MemFunctionInfo.isMemFunction(*Call)) + if (isMemCall(*Call)) return false; // If it's not a system call, assume it frees memory. @@ -3023,6 +3075,18 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux( return State; } +bool MallocChecker::isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, + SVal ArgVal) const { + if (!KernelZeroSizePtrValue) + KernelZeroSizePtrValue = + tryExpandAsInteger("ZERO_SIZE_PTR", C.getPreprocessor()); + + const llvm::APSInt *ArgValKnown = + C.getSValBuilder().getKnownValue(State, ArgVal); + return ArgValKnown && *KernelZeroSizePtrValue && + ArgValKnown->getSExtValue() == **KernelZeroSizePtrValue; +} + static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState) { ReallocPairsTy currMap = currState->get(); @@ -3285,11 +3349,11 @@ void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) { void ento::registerDynamicMemoryModeling(CheckerManager &mgr) { auto *checker = mgr.registerChecker(); - checker->MemFunctionInfo.ShouldIncludeOwnershipAnnotatedFunctions = + checker->ShouldIncludeOwnershipAnnotatedFunctions = mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic"); } -bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) { +bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) { return true; } @@ -3301,7 +3365,7 @@ bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) { mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name(const LangOptions &LO) { return true; } + bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(MallocChecker) REGISTER_CHECKER(NewDeleteChecker) diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp index 4fd06f24c5bc6..e31630f63b5ac 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp @@ -337,6 +337,6 @@ void ento::registerMallocOverflowSecurityChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterMallocOverflowSecurityChecker(const LangOptions &LO) { +bool ento::shouldRegisterMallocOverflowSecurityChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index b5881a9e65338..71f593cb2b561 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -250,6 +250,6 @@ void ento::registerMallocSizeofChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterMallocSizeofChecker(const LangOptions &LO) { +bool ento::shouldRegisterMallocSizeofChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp index 143910588959e..d170b875856c2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp @@ -290,6 +290,6 @@ void ento::registerMismatchedIteratorChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterMismatchedIteratorChecker(const LangOptions &LO) { +bool ento::shouldRegisterMismatchedIteratorChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp index ceea62160545e..5d63d6efd2341 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp @@ -88,6 +88,6 @@ void ento::registerMmapWriteExecChecker(CheckerManager &mgr) { .getCheckerIntegerOption(Mwec, "MmapProtRead"); } -bool ento::shouldRegisterMmapWriteExecChecker(const LangOptions &LO) { +bool ento::shouldRegisterMmapWriteExecChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp index 40eb113e3f8e9..7f0519c695b0f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -757,6 +757,6 @@ void ento::registerMoveChecker(CheckerManager &mgr) { mgr.getAnalyzerOptions().getCheckerStringOption(chk, "WarnOn"), mgr); } -bool ento::shouldRegisterMoveChecker(const LangOptions &LO) { +bool ento::shouldRegisterMoveChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index 41b7fe5e43b6f..be17e401fb534 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -80,6 +80,7 @@ void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterNSAutoreleasePoolChecker(const LangOptions &LO) { +bool ento::shouldRegisterNSAutoreleasePoolChecker(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.getGC() != LangOptions::NonGC; } diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 85370bf133cd7..2dee1e459a060 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -312,7 +312,7 @@ void ento::registerNSOrCFErrorDerefChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterNSOrCFErrorDerefChecker(const LangOptions &LO) { +bool ento::shouldRegisterNSOrCFErrorDerefChecker(const CheckerManager &mgr) { return true; } @@ -322,7 +322,7 @@ void ento::registerNSErrorChecker(CheckerManager &mgr) { checker->ShouldCheckNSError = true; } -bool ento::shouldRegisterNSErrorChecker(const LangOptions &LO) { +bool ento::shouldRegisterNSErrorChecker(const CheckerManager &mgr) { return true; } @@ -332,6 +332,6 @@ void ento::registerCFErrorChecker(CheckerManager &mgr) { checker->ShouldCheckCFError = true; } -bool ento::shouldRegisterCFErrorChecker(const LangOptions &LO) { +bool ento::shouldRegisterCFErrorChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index fc34255bf6c95..af208e8673187 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp @@ -143,6 +143,6 @@ void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterNoReturnFunctionChecker(const LangOptions &LO) { +bool ento::shouldRegisterNoReturnFunctionChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp index 6ffc89745365c..8c7975a513a07 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp @@ -226,6 +226,6 @@ void ento::registerNonNullParamChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterNonNullParamChecker(const LangOptions &LO) { +bool ento::shouldRegisterNonNullParamChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp index 6efba433eed22..80b705fb73926 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp @@ -147,6 +147,6 @@ void ento::registerNonnullGlobalConstantsChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterNonnullGlobalConstantsChecker(const LangOptions &LO) { +bool ento::shouldRegisterNonnullGlobalConstantsChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 922048733c7c4..0b8d100992a22 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -508,13 +508,7 @@ void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const { /// return expressions of ObjC types when the return type of the function or /// method is non-null but the express is not. static const Expr *lookThroughImplicitCasts(const Expr *E) { - assert(E); - - while (auto *ICE = dyn_cast(E)) { - E = ICE->getSubExpr(); - } - - return E; + return E->IgnoreImpCasts(); } /// This method check when nullable pointer or null value is returned from a @@ -1188,7 +1182,7 @@ void ento::registerNullabilityBase(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterNullabilityBase(const LangOptions &LO) { +bool ento::shouldRegisterNullabilityBase(const CheckerManager &mgr) { return true; } @@ -1204,7 +1198,7 @@ bool ento::shouldRegisterNullabilityBase(const LangOptions &LO) { checker, "NoDiagnoseCallsToSystemHeaders", true); \ } \ \ - bool ento::shouldRegister##name##Checker(const LangOptions &LO) { \ + bool ento::shouldRegister##name##Checker(const CheckerManager &mgr) { \ return true; \ } diff --git a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp index 1053424ae6faa..df69254ead263 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp @@ -349,6 +349,6 @@ void ento::registerNumberObjectConversionChecker(CheckerManager &Mgr) { Mgr.getAnalyzerOptions().getCheckerBooleanOption(Chk, "Pedantic"); } -bool ento::shouldRegisterNumberObjectConversionChecker(const LangOptions &LO) { +bool ento::shouldRegisterNumberObjectConversionChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp b/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp index 90d69b81305c8..53ed0e187a4ce 100644 --- a/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/OSObjectCStyleCast.cpp @@ -84,6 +84,6 @@ void ento::registerOSObjectCStyleCast(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterOSObjectCStyleCast(const LangOptions &LO) { +bool ento::shouldRegisterOSObjectCStyleCast(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index 0e25817c87932..43af4bb142867 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -91,6 +91,7 @@ void ento::registerObjCAtSyncChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCAtSyncChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCAtSyncChecker(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.ObjC; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp index 9d587c5856500..f36e971bb8ba6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCAutoreleaseWriteChecker.cpp @@ -206,6 +206,6 @@ void ento::registerAutoreleaseWriteChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterAutoreleaseWriteChecker(const LangOptions &LO) { +bool ento::shouldRegisterAutoreleaseWriteChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp index 4450c464f89d3..8428b2294ba6f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp @@ -172,6 +172,6 @@ void ento::registerObjCContainersASTChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCContainersASTChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCContainersASTChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp index 8abb926d4862f..ff19d7a2b9d4c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp @@ -188,6 +188,6 @@ void ento::registerObjCContainersChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCContainersChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCContainersChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp index 1870c08432de3..24e2a4dea922e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp @@ -221,7 +221,7 @@ void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterObjCSuperCallChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCSuperCallChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp index 9a49200545e37..4636fd1605118 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp @@ -79,6 +79,6 @@ void ento::registerObjCPropertyChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterObjCPropertyChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCPropertyChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 344285750f0e8..17d3c042ac403 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -437,6 +437,6 @@ void ento::registerObjCSelfInitChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCSelfInitChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCSelfInitChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp index 0575be8453743..39ffbca8d393a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCSuperDeallocChecker.cpp @@ -284,6 +284,6 @@ void ento::registerObjCSuperDeallocChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterObjCSuperDeallocChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCSuperDeallocChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index cb47704515723..c9828c36a06a0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp @@ -186,6 +186,6 @@ void ento::registerObjCUnusedIvarsChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterObjCUnusedIvarsChecker(const LangOptions &LO) { +bool ento::shouldRegisterObjCUnusedIvarsChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp index 4a3c2b8cd40e2..0b00664c7c104 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp @@ -353,6 +353,6 @@ void ento::registerPaddingChecker(CheckerManager &Mgr) { Checker, "AllowedPad", "a non-negative value"); } -bool ento::shouldRegisterPaddingChecker(const LangOptions &LO) { +bool ento::shouldRegisterPaddingChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp index 259f23abdc958..d3e2849a0ce69 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -343,6 +343,6 @@ void ento::registerPointerArithChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterPointerArithChecker(const LangOptions &LO) { +bool ento::shouldRegisterPointerArithChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp index 307e59b8eebc4..8aca6d009cdb0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerIterationChecker.cpp @@ -95,6 +95,7 @@ void ento::registerPointerIterationChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterPointerIterationChecker(const LangOptions &LO) { +bool ento::shouldRegisterPointerIterationChecker(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.CPlusPlus; } diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp index a3bfac97e40a7..8eee4df473e8f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp @@ -108,6 +108,7 @@ void ento::registerPointerSortingChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterPointerSortingChecker(const LangOptions &LO) { +bool ento::shouldRegisterPointerSortingChecker(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.CPlusPlus; } diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index 88d0eb2ae7484..81c19d9a09400 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -74,6 +74,6 @@ void ento::registerPointerSubChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterPointerSubChecker(const LangOptions &LO) { +bool ento::shouldRegisterPointerSubChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index b89e1671cfadc..285d2da104f1a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -725,7 +725,7 @@ void ento::registerPthreadLockBase(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterPthreadLockBase(const LangOptions &LO) { return true; } +bool ento::shouldRegisterPthreadLockBase(const CheckerManager &mgr) { return true; } #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) { \ @@ -735,7 +735,7 @@ bool ento::shouldRegisterPthreadLockBase(const LangOptions &LO) { return true; } mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name(const LangOptions &LO) { return true; } + bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(PthreadLockChecker) REGISTER_CHECKER(FuchsiaLockChecker) diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 6f8cb1432bb11..4bf9beb365f66 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -1477,7 +1477,7 @@ void ento::registerRetainCountBase(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterRetainCountBase(const LangOptions &LO) { +bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) { return true; } @@ -1485,7 +1485,7 @@ bool ento::shouldRegisterRetainCountBase(const LangOptions &LO) { // it should be possible to enable the NS/CF retain count checker as // osx.cocoa.RetainCount, and it should be possible to disable // osx.OSObjectRetainCount using osx.cocoa.RetainCount:CheckOSObject=false. -static bool getOption(AnalyzerOptions &Options, +static bool getOption(const AnalyzerOptions &Options, StringRef Postfix, StringRef Value) { auto I = Options.Config.find( @@ -1503,7 +1503,7 @@ void ento::registerRetainCountChecker(CheckerManager &Mgr) { "true"); } -bool ento::shouldRegisterRetainCountChecker(const LangOptions &LO) { +bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) { return true; } @@ -1515,6 +1515,6 @@ void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) { Chk->TrackOSObjects = true; } -bool ento::shouldRegisterOSObjectRetainCountChecker(const LangOptions &LO) { +bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index 8a89649aae777..599d4f306aa13 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -91,6 +91,6 @@ void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterReturnPointerRangeChecker(const LangOptions &LO) { +bool ento::shouldRegisterReturnPointerRangeChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index fbd15d864424e..5266cbf86b44f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -122,6 +122,6 @@ void ento::registerReturnUndefChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterReturnUndefChecker(const LangOptions &LO) { +bool ento::shouldRegisterReturnUndefChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp index f98065492726b..14ecede170832 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp @@ -165,6 +165,6 @@ void ento::registerReturnValueChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterReturnValueChecker(const LangOptions &LO) { +bool ento::shouldRegisterReturnValueChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp index 5e305aa709b64..d9dc72ddaa218 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RunLoopAutoreleaseLeakChecker.cpp @@ -203,6 +203,6 @@ void ento::registerRunLoopAutoreleaseLeakChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterRunLoopAutoreleaseLeakChecker(const LangOptions &LO) { +bool ento::shouldRegisterRunLoopAutoreleaseLeakChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp index 9452ccdc46c96..933e0146ff59b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp @@ -174,7 +174,7 @@ void ento::registerSTLAlgorithmModeling(CheckerManager &Mgr) { "AggressiveStdFindModeling"); } -bool ento::shouldRegisterSTLAlgorithmModeling(const LangOptions &LO) { +bool ento::shouldRegisterSTLAlgorithmModeling(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp index 8193bcbef4cdf..8d380ed1b93de 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -271,6 +271,6 @@ void ento::registerSimpleStreamChecker(CheckerManager &mgr) { } // This checker should be enabled regardless of how language options are set. -bool ento::shouldRegisterSimpleStreamChecker(const LangOptions &LO) { +bool ento::shouldRegisterSimpleStreamChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp index fd372aafa50d9..8250fd46b9266 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -67,6 +67,7 @@ void ento::registerSmartPtrModeling(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterSmartPtrModeling(const LangOptions &LO) { +bool ento::shouldRegisterSmartPtrModeling(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.CPlusPlus; } diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 7285d27495a7c..21fc65a8e4f1a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -365,7 +365,7 @@ void ento::registerStackAddrEscapeBase(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterStackAddrEscapeBase(const LangOptions &LO) { +bool ento::shouldRegisterStackAddrEscapeBase(const CheckerManager &mgr) { return true; } @@ -376,7 +376,7 @@ bool ento::shouldRegisterStackAddrEscapeBase(const LangOptions &LO) { Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \ } \ \ - bool ento::shouldRegister##name(const LangOptions &LO) { \ + bool ento::shouldRegister##name(const CheckerManager &mgr) { \ return true; \ } diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index ff296e7ea46b2..f03696daab0b0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -190,6 +190,9 @@ class StdLibraryFunctionsChecker ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call, const Summary &Summary) const override { SVal V = getArgSVal(Call, getArgNo()); + if (V.isUndef()) + return State; + DefinedOrUnknownSVal L = V.castAs(); if (!L.getAs()) return State; @@ -303,7 +306,11 @@ class StdLibraryFunctionsChecker void checkPostCall(const CallEvent &Call, CheckerContext &C) const; bool evalCall(const CallEvent &Call, CheckerContext &C) const; - enum CheckKind { CK_StdCLibraryFunctionArgsChecker, CK_NumCheckKinds }; + enum CheckKind { + CK_StdCLibraryFunctionArgsChecker, + CK_StdCLibraryFunctionsTesterChecker, + CK_NumCheckKinds + }; DefaultBool ChecksEnabled[CK_NumCheckKinds]; CheckerNameRef CheckNames[CK_NumCheckKinds]; @@ -452,23 +459,26 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call, const Summary &Summary = *FoundSummary; ProgramStateRef State = C.getState(); + ProgramStateRef NewState = State; for (const ValueConstraintPtr& VC : Summary.ArgConstraints) { - ProgramStateRef SuccessSt = VC->apply(State, Call, Summary); - ProgramStateRef FailureSt = VC->negate()->apply(State, Call, Summary); + ProgramStateRef SuccessSt = VC->apply(NewState, Call, Summary); + ProgramStateRef FailureSt = VC->negate()->apply(NewState, Call, Summary); // The argument constraint is not satisfied. if (FailureSt && !SuccessSt) { - if (ExplodedNode *N = C.generateErrorNode(State)) + if (ExplodedNode *N = C.generateErrorNode(NewState)) reportBug(Call, N, C); break; } else { - // Apply the constraint even if we cannot reason about the argument. This - // means both SuccessSt and FailureSt can be true. If we weren't applying - // the constraint that would mean that symbolic execution continues on a - // code whose behaviour is undefined. + // We will apply the constraint even if we cannot reason about the + // argument. This means both SuccessSt and FailureSt can be true. If we + // weren't applying the constraint that would mean that symbolic + // execution continues on a code whose behaviour is undefined. assert(SuccessSt); - C.addTransition(SuccessSt); + NewState = SuccessSt; } } + if (NewState && NewState != State) + C.addTransition(NewState); } void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call, @@ -933,13 +943,39 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( {"getdelim", Summaries{Getline(IntTy, IntMax), Getline(LongTy, LongMax), Getline(LongLongTy, LongLongMax)}}, }; + + // Functions for testing. + if (ChecksEnabled[CK_StdCLibraryFunctionsTesterChecker]) { + llvm::StringMap TestFunctionSummaryMap = { + {"__two_constrained_args", + Summaries{ + Summary(ArgTypes{IntTy, IntTy}, RetType{IntTy}, EvalCallAsPure) + .ArgConstraint( + ArgumentCondition(0U, WithinRange, SingleValue(1))) + .ArgConstraint( + ArgumentCondition(1U, WithinRange, SingleValue(1)))}}, + {"__arg_constrained_twice", + Summaries{Summary(ArgTypes{IntTy}, RetType{IntTy}, EvalCallAsPure) + .ArgConstraint( + ArgumentCondition(0U, OutOfRange, SingleValue(1))) + .ArgConstraint( + ArgumentCondition(0U, OutOfRange, SingleValue(2)))}}, + }; + for (auto &E : TestFunctionSummaryMap) { + auto InsertRes = + FunctionSummaryMap.insert({std::string(E.getKey()), E.getValue()}); + assert(InsertRes.second && + "Test functions must not clash with modeled functions"); + (void)InsertRes; + } + } } void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterStdCLibraryFunctionsChecker(const LangOptions &LO) { +bool ento::shouldRegisterStdCLibraryFunctionsChecker(const CheckerManager &mgr) { return true; } @@ -952,6 +988,7 @@ bool ento::shouldRegisterStdCLibraryFunctionsChecker(const LangOptions &LO) { mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name(const LangOptions &LO) { return true; } + bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } REGISTER_CHECKER(StdCLibraryFunctionArgsChecker) +REGISTER_CHECKER(StdCLibraryFunctionsTesterChecker) diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 7e5bf7c376f0f..4b20fcdc9a15f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -441,4 +441,6 @@ void ento::registerStreamChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterStreamChecker(const LangOptions &LO) { return true; } +bool ento::shouldRegisterStreamChecker(const CheckerManager &mgr) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp index f81705304f3ab..916977c10c0c1 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp @@ -63,6 +63,6 @@ void ento::registerTaintTesterChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterTaintTesterChecker(const LangOptions &LO) { +bool ento::shouldRegisterTaintTesterChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp index 3663b09636924..eeec807ccee40 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp @@ -261,6 +261,6 @@ void ento::registerTestAfterDivZeroChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterTestAfterDivZeroChecker(const LangOptions &LO) { +bool ento::shouldRegisterTestAfterDivZeroChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp index 73183aa468f65..2f316bd3b20db 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TraversalChecker.cpp @@ -64,7 +64,7 @@ void ento::registerTraversalDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterTraversalDumper(const LangOptions &LO) { +bool ento::shouldRegisterTraversalDumper(const CheckerManager &mgr) { return true; } @@ -116,6 +116,6 @@ void ento::registerCallDumper(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterCallDumper(const LangOptions &LO) { +bool ento::shouldRegisterCallDumper(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp index 62a4c2ab0209c..5cc7131725274 100644 --- a/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/TrustNonnullChecker.cpp @@ -252,6 +252,6 @@ void ento::registerTrustNonnullChecker(CheckerManager &Mgr) { Mgr.registerChecker(Mgr.getASTContext()); } -bool ento::shouldRegisterTrustNonnullChecker(const LangOptions &LO) { +bool ento::shouldRegisterTrustNonnullChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index 247cba7dc9333..3e0caaf79ca09 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -110,6 +110,6 @@ void ento::registerUndefBranchChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterUndefBranchChecker(const LangOptions &LO) { +bool ento::shouldRegisterUndefBranchChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index 7b581bef39001..e457513d8de44 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -101,6 +101,6 @@ void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterUndefCapturedBlockVarChecker(const LangOptions &LO) { +bool ento::shouldRegisterUndefCapturedBlockVarChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 9a37786037a29..392da48180983 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -187,6 +187,6 @@ void ento::registerUndefResultChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterUndefResultChecker(const LangOptions &LO) { +bool ento::shouldRegisterUndefResultChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index 2f075eaeb03bf..fdefe75e8201d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -62,6 +62,6 @@ void ento::registerUndefinedArraySubscriptChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterUndefinedArraySubscriptChecker(const LangOptions &LO) { +bool ento::shouldRegisterUndefinedArraySubscriptChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 277a8a1433282..05f8f6084c0b6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -120,6 +120,6 @@ void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterUndefinedAssignmentChecker(const LangOptions &LO) { +bool ento::shouldRegisterUndefinedAssignmentChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp index 14f551403d98d..e0be718decb29 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp @@ -608,7 +608,7 @@ std::string clang::ento::getVariableName(const FieldDecl *Field) { void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) { auto Chk = Mgr.registerChecker(); - AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions(); + const AnalyzerOptions &AnOpts = Mgr.getAnalyzerOptions(); UninitObjCheckerOptions &ChOpts = Chk->Opts; ChOpts.IsPedantic = AnOpts.getCheckerBooleanOption(Chk, "Pedantic"); @@ -628,6 +628,6 @@ void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) { "\"" + ErrorMsg + "\""); } -bool ento::shouldRegisterUninitializedObjectChecker(const LangOptions &LO) { +bool ento::shouldRegisterUninitializedObjectChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index f4e225d836f38..6ea8451512f3a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -503,7 +503,7 @@ void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE, mgr.registerChecker(); \ } \ \ - bool ento::shouldRegister##CHECKERNAME(const LangOptions &LO) { \ + bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \ return true; \ } diff --git a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index 65dd82675df9b..74eec81ffb3e5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -257,6 +257,6 @@ void ento::registerUnreachableCodeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterUnreachableCodeChecker(const LangOptions &LO) { +bool ento::shouldRegisterUnreachableCodeChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index 92e81edafbf30..21e8b9653039b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -187,6 +187,6 @@ void ento::registerVLASizeChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterVLASizeChecker(const LangOptions &LO) { +bool ento::shouldRegisterVLASizeChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp index a3610514a924b..dde5912b6d6ee 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp @@ -404,7 +404,7 @@ void ento::registerValistBase(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterValistBase(const LangOptions &LO) { +bool ento::shouldRegisterValistBase(const CheckerManager &mgr) { return true; } @@ -416,7 +416,7 @@ bool ento::shouldRegisterValistBase(const LangOptions &LO) { mgr.getCurrentCheckerName(); \ } \ \ - bool ento::shouldRegister##name##Checker(const LangOptions &LO) { \ + bool ento::shouldRegister##name##Checker(const CheckerManager &mgr) { \ return true; \ } diff --git a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp index 077a34810db77..8f147026ae192 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp @@ -217,6 +217,6 @@ void ento::registerVforkChecker(CheckerManager &mgr) { mgr.registerChecker(); } -bool ento::shouldRegisterVforkChecker(const LangOptions &LO) { +bool ento::shouldRegisterVforkChecker(const CheckerManager &mgr) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index fd93fc33115f5..f49ee5fa5ad37 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -224,14 +224,17 @@ void ento::registerVirtualCallChecker(CheckerManager &Mgr) { } } -bool ento::shouldRegisterVirtualCallModeling(const LangOptions &LO) { +bool ento::shouldRegisterVirtualCallModeling(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.CPlusPlus; } -bool ento::shouldRegisterPureVirtualCallChecker(const LangOptions &LO) { +bool ento::shouldRegisterPureVirtualCallChecker(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.CPlusPlus; } -bool ento::shouldRegisterVirtualCallChecker(const LangOptions &LO) { +bool ento::shouldRegisterVirtualCallChecker(const CheckerManager &mgr) { + const LangOptions &LO = mgr.getLangOpts(); return LO.CPlusPlus; } diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp index b712e77cf6d2b..1c67bbd77ec88 100644 --- a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp @@ -63,4 +63,4 @@ void ento::registerPutenvWithAuto(CheckerManager &Mgr) { Mgr.registerChecker(); } -bool ento::shouldRegisterPutenvWithAuto(const LangOptions &) { return true; } +bool ento::shouldRegisterPutenvWithAuto(const CheckerManager &) { return true; } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp b/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp index e43b172d018d4..4b63ebc40edeb 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerHelpers.cpp @@ -126,9 +126,6 @@ llvm::Optional tryExpandAsInteger(StringRef Macro, if (!T.isOneOf(tok::l_paren, tok::r_paren)) FilteredTokens.push_back(T); - if (FilteredTokens.size() > 2) - return llvm::None; - // Parse an integer at the end of the macro definition. const Token &T = FilteredTokens.back(); if (!T.isLiteral()) @@ -140,11 +137,10 @@ llvm::Optional tryExpandAsInteger(StringRef Macro, return llvm::None; // Parse an optional minus sign. - if (FilteredTokens.size() == 2) { - if (FilteredTokens.front().is(tok::minus)) + size_t Size = FilteredTokens.size(); + if (Size >= 2) { + if (FilteredTokens[Size - 2].is(tok::minus)) IntValue = -IntValue; - else - return llvm::None; } return IntValue.getSExtValue(); diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index ce5e4a46d3e2c..17c66cd232791 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -64,10 +64,9 @@ void CheckerManager::reportInvalidCheckerOptionValue( const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) const { - Context.getDiagnostics() - .Report(diag::err_analyzer_checker_option_invalid_input) - << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() - << ExpectedValueDesc; + getDiagnostics().Report(diag::err_analyzer_checker_option_invalid_input) + << (llvm::Twine() + C->getTagDescription() + ":" + OptionName).str() + << ExpectedValueDesc; } //===----------------------------------------------------------------------===// @@ -903,8 +902,3 @@ CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { Checkers.push_back(Info.CheckFn); return Checkers; } - -CheckerManager::~CheckerManager() { - for (const auto &CheckerDtor : CheckerDtors) - CheckerDtor(); -} diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index b9adee87436a9..1f0d89d59120e 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1413,6 +1413,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::CXXNullPtrLiteralExprClass: case Stmt::OMPArraySectionExprClass: + case Stmt::OMPArrayShapingExprClass: + case Stmt::OMPIteratorExprClass: case Stmt::TypeTraitExprClass: { Bldr.takeNodes(Pred); ExplodedNodeSet preVisit; @@ -3173,9 +3175,10 @@ std::string ExprEngine::DumpGraph(bool trim, StringRef Filename) { /*Title=*/"Exploded Graph", /*Filename=*/std::string(Filename)); } -#endif +#else llvm::errs() << "Warning: dumping graph requires assertions" << "\n"; return ""; +#endif } std::string ExprEngine::DumpGraph(ArrayRef Nodes, diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 2e3aa0669061f..74c689730e58d 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -33,7 +33,6 @@ #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" @@ -209,8 +208,8 @@ class AnalysisConsumer : public AnalysisASTConsumer, void Initialize(ASTContext &Context) override { Ctx = &Context; - checkerMgr = createCheckerManager( - *Ctx, *Opts, Plugins, CheckerRegistrationFns, PP.getDiagnostics()); + checkerMgr = std::make_unique(*Ctx, *Opts, PP, Plugins, + CheckerRegistrationFns); Mgr = std::make_unique(*Ctx, PP, PathConsumers, CreateStoreMgr, CreateConstraintMgr, diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp similarity index 69% rename from clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp rename to clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp index f4f06e32cd1d7..d589e69bdf347 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp @@ -10,8 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" +#include "clang/StaticAnalyzer/Frontend/AnalyzerHelpFlags.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -24,53 +25,34 @@ using namespace clang; using namespace ento; -std::unique_ptr ento::createCheckerManager( - ASTContext &context, - AnalyzerOptions &opts, - ArrayRef plugins, - ArrayRef> checkerRegistrationFns, - DiagnosticsEngine &diags) { - auto checkerMgr = std::make_unique(context, opts); - - CheckerRegistry allCheckers(plugins, diags, opts, context.getLangOpts(), - checkerRegistrationFns); - - allCheckers.initializeManager(*checkerMgr); - allCheckers.validateCheckerOptions(); - checkerMgr->finishedCheckerRegistration(); - - return checkerMgr; -} - -void ento::printCheckerHelp(raw_ostream &out, ArrayRef plugins, - AnalyzerOptions &anopts, - DiagnosticsEngine &diags, - const LangOptions &langOpts) { +void ento::printCheckerHelp(raw_ostream &out, CompilerInstance &CI) { out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n"; out << "USAGE: -analyzer-checker \n\n"; - CheckerRegistry(plugins, diags, anopts, langOpts) - .printCheckerWithDescList(out); + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printCheckerWithDescList(out); } -void ento::printEnabledCheckerList(raw_ostream &out, - ArrayRef plugins, - AnalyzerOptions &anopts, - DiagnosticsEngine &diags, - const LangOptions &langOpts) { +void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) { out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n"; - CheckerRegistry(plugins, diags, anopts, langOpts) - .printEnabledCheckerList(out); + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printEnabledCheckerList(out); } -void ento::printCheckerConfigList(raw_ostream &OS, - ArrayRef plugins, - AnalyzerOptions &opts, - DiagnosticsEngine &diags, - const LangOptions &LangOpts) { - CheckerRegistry(plugins, diags, opts, LangOpts) - .printCheckerOptionList(OS); +void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) { + + auto CheckerMgr = std::make_unique( + *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(), + CI.getFrontendOpts().Plugins); + + CheckerMgr->getCheckerRegistry().printCheckerOptionList(out); } void ento::printAnalyzerConfigList(raw_ostream &out) { diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 5e7dd8f18cd73..0c100a121f777 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -6,14 +6,16 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangStaticAnalyzerFrontend AnalysisConsumer.cpp - CheckerRegistration.cpp + AnalyzerHelpFlags.cpp CheckerRegistry.cpp + CreateCheckerManager.cpp FrontendActions.cpp ModelConsumer.cpp ModelInjector.cpp LINK_LIBS clangAST + clangASTMatchers clangAnalysis clangBasic clangCrossTU diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index 4af204474494f..e5583549a01f4 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -109,9 +109,9 @@ CheckerRegistry::getMutableCheckersForCmdLineArg(StringRef CmdLineArg) { CheckerRegistry::CheckerRegistry( ArrayRef Plugins, DiagnosticsEngine &Diags, - AnalyzerOptions &AnOpts, const LangOptions &LangOpts, + AnalyzerOptions &AnOpts, ArrayRef> CheckerRegistrationFns) - : Diags(Diags), AnOpts(AnOpts), LangOpts(LangOpts) { + : Diags(Diags), AnOpts(AnOpts) { // Register builtin checkers. #define GET_CHECKERS @@ -179,12 +179,16 @@ CheckerRegistry::CheckerRegistry( addDependency(FULLNAME, DEPENDENCY); #define GET_CHECKER_OPTIONS -#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ - addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); +#define CHECKER_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ + DEVELOPMENT_STATUS, IS_HIDDEN) \ + addCheckerOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ + DEVELOPMENT_STATUS, IS_HIDDEN); #define GET_PACKAGE_OPTIONS -#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, DEVELOPMENT_STATUS, IS_HIDDEN) \ - addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, DEVELOPMENT_STATUS, IS_HIDDEN); +#define PACKAGE_OPTION(TYPE, FULLNAME, CMDFLAG, DESC, DEFAULT_VAL, \ + DEVELOPMENT_STATUS, IS_HIDDEN) \ + addPackageOption(TYPE, FULLNAME, CMDFLAG, DEFAULT_VAL, DESC, \ + DEVELOPMENT_STATUS, IS_HIDDEN); #include "clang/StaticAnalyzer/Checkers/Checkers.inc" #undef CHECKER_DEPENDENCY @@ -213,24 +217,53 @@ CheckerRegistry::CheckerRegistry( : StateFromCmdLine::State_Disabled; } } + validateCheckerOptions(); +} + +/// Collects dependenies in \p enabledCheckers. Return None on failure. +LLVM_NODISCARD +static llvm::Optional +collectDependencies(const CheckerRegistry::CheckerInfo &checker, + const CheckerManager &Mgr); + +void CheckerRegistry::initializeRegistry(const CheckerManager &Mgr) { + for (const CheckerInfo &Checker : Checkers) { + if (!Checker.isEnabled(Mgr)) + continue; + + // Recursively enable its dependencies. + llvm::Optional Deps = collectDependencies(Checker, Mgr); + + if (!Deps) { + // If we failed to enable any of the dependencies, don't enable this + // checker. + continue; + } + + // Note that set_union also preserves the order of insertion. + EnabledCheckers.set_union(*Deps); + + // Enable the checker. + EnabledCheckers.insert(&Checker); + } } /// Collects dependencies in \p ret, returns false on failure. static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const LangOptions &LO, + const CheckerManager &Mgr, CheckerRegistry::CheckerInfoSet &Ret); /// Collects dependenies in \p enabledCheckers. Return None on failure. LLVM_NODISCARD static llvm::Optional collectDependencies(const CheckerRegistry::CheckerInfo &checker, - const LangOptions &LO) { + const CheckerManager &Mgr) { CheckerRegistry::CheckerInfoSet Ret; // Add dependencies to the enabled checkers only if all of them can be // enabled. - if (!collectDependenciesImpl(checker.Dependencies, LO, Ret)) + if (!collectDependenciesImpl(checker.Dependencies, Mgr, Ret)) return None; return Ret; @@ -238,16 +271,16 @@ collectDependencies(const CheckerRegistry::CheckerInfo &checker, static bool collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, - const LangOptions &LO, + const CheckerManager &Mgr, CheckerRegistry::CheckerInfoSet &Ret) { for (const CheckerRegistry::CheckerInfo *Dependency : Deps) { - if (Dependency->isDisabled(LO)) + if (Dependency->isDisabled(Mgr)) return false; // Collect dependencies recursively. - if (!collectDependenciesImpl(Dependency->Dependencies, LO, Ret)) + if (!collectDependenciesImpl(Dependency->Dependencies, Mgr, Ret)) return false; Ret.insert(Dependency); @@ -256,34 +289,6 @@ collectDependenciesImpl(const CheckerRegistry::ConstCheckerInfoList &Deps, return true; } -CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const { - - CheckerInfoSet EnabledCheckers; - - for (const CheckerInfo &Checker : Checkers) { - if (!Checker.isEnabled(LangOpts)) - continue; - - // Recursively enable its dependencies. - llvm::Optional Deps = - collectDependencies(Checker, LangOpts); - - if (!Deps) { - // If we failed to enable any of the dependencies, don't enable this - // checker. - continue; - } - - // Note that set_union also preserves the order of insertion. - EnabledCheckers.set_union(*Deps); - - // Enable the checker. - EnabledCheckers.insert(&Checker); - } - - return EnabledCheckers; -} - void CheckerRegistry::resolveDependencies() { for (const std::pair &Entry : Dependencies) { auto CheckerIt = binaryFind(Checkers, Entry.first); @@ -298,8 +303,6 @@ void CheckerRegistry::resolveDependencies() { CheckerIt->Dependencies.emplace_back(&*DependencyIt); } - - Dependencies.clear(); } void CheckerRegistry::addDependency(StringRef FullName, StringRef Dependency) { @@ -378,14 +381,12 @@ void CheckerRegistry::resolveCheckerAndPackageOptions() { insertOptionToCollection(CheckerOptEntry.first, Checkers, CheckerOptEntry.second, AnOpts, Diags); } - CheckerOptions.clear(); for (const std::pair &PackageOptEntry : PackageOptions) { insertOptionToCollection(PackageOptEntry.first, Packages, PackageOptEntry.second, AnOpts, Diags); } - PackageOptions.clear(); } void CheckerRegistry::addPackage(StringRef FullName) { @@ -432,11 +433,8 @@ void CheckerRegistry::addCheckerOption(StringRef OptionType, } void CheckerRegistry::initializeManager(CheckerManager &CheckerMgr) const { - // Collect checkers enabled by the options. - CheckerInfoSet enabledCheckers = getEnabledCheckers(); - // Initialize the CheckerManager with all enabled checkers. - for (const auto *Checker : enabledCheckers) { + for (const auto *Checker : EnabledCheckers) { CheckerMgr.setCurrentCheckerName(CheckerNameRef(Checker->FullName)); Checker->Initialize(CheckerMgr); } @@ -505,6 +503,10 @@ void CheckerRegistry::validateCheckerOptions() const { } } +//===----------------------------------------------------------------------===// +// Printing functions. +//===----------------------------------------------------------------------===// + void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, size_t MaxNameChars) const { // FIXME: Print available packages. @@ -556,9 +558,6 @@ void CheckerRegistry::printCheckerWithDescList(raw_ostream &Out, } void CheckerRegistry::printEnabledCheckerList(raw_ostream &Out) const { - // Collect checkers enabled by the options. - CheckerInfoSet EnabledCheckers = getEnabledCheckers(); - for (const auto *i : EnabledCheckers) Out << i->FullName << '\n'; } diff --git a/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp new file mode 100644 index 0000000000000..140f807514439 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Frontend/CreateCheckerManager.cpp @@ -0,0 +1,49 @@ +//===- CheckerManager.h - Static Analyzer Checker Manager -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Defines the Static Analyzer Checker Manager. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include + +namespace clang { +namespace ento { + +CheckerManager::CheckerManager( + ASTContext &Context, AnalyzerOptions &AOptions, const Preprocessor &PP, + ArrayRef plugins, + ArrayRef> checkerRegistrationFns) + : Context(&Context), LangOpts(Context.getLangOpts()), AOptions(AOptions), + PP(&PP), Diags(Context.getDiagnostics()), + Registry( + std::make_unique(plugins, Context.getDiagnostics(), + AOptions, checkerRegistrationFns)) { + Registry->initializeRegistry(*this); + Registry->initializeManager(*this); + finishedCheckerRegistration(); +} + +CheckerManager::CheckerManager(AnalyzerOptions &AOptions, + const LangOptions &LangOpts, + DiagnosticsEngine &Diags, + ArrayRef plugins) + : LangOpts(LangOpts), AOptions(AOptions), Diags(Diags), + Registry(std::make_unique(plugins, Diags, AOptions)) { + Registry->initializeRegistry(*this); +} + +CheckerManager::~CheckerManager() { + for (const auto &CheckerDtor : CheckerDtors) + CheckerDtor(); +} + +} // namespace ento +} // namespace clang diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 82c87ba02b744..11058edec615d 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -44,15 +44,6 @@ using namespace clang; LLVM_ATTRIBUTE_UNUSED static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; } -static SourceLocation getQualifiedNameStart(DeclaratorDecl *D) { - auto DN = D->getDeclName(); - bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo(); - if (IsAnonymous) - return SourceLocation(); - return D->getQualifierLoc() ? D->getQualifierLoc().getBeginLoc() - : D->getLocation(); -} - namespace { /// Get start location of the Declarator from the TypeLoc. /// E.g.: @@ -142,8 +133,9 @@ static SourceRange getDeclaratorRange(const SourceManager &SM, TypeLoc T, End = Name; } if (Initializer.isValid()) { - assert(SM.isBeforeInTranslationUnit(End, Initializer.getEnd())); - End = Initializer.getEnd(); + auto InitializerEnd = Initializer.getEnd(); + assert(SM.isBeforeInTranslationUnit(End, InitializerEnd) || End == InitializerEnd); + End = InitializerEnd; } return SourceRange(Start, End); } @@ -212,10 +204,6 @@ class syntax::TreeBuilder { foldNode(Range, New, nullptr); } - /// Must be called with the range of each `DeclaratorDecl`. Ensures the - /// corresponding declarator nodes are covered by `SimpleDeclaration`. - void noticeDeclRange(llvm::ArrayRef Range); - /// Notifies that we should not consume trailing semicolon when computing /// token range of \p D. void noticeDeclWithoutSemicolon(Decl *D); @@ -237,11 +225,6 @@ class syntax::TreeBuilder { void markChild(syntax::Node *N, NodeRole R); /// Set role for the syntax node matching \p N. void markChild(ASTPtr N, NodeRole R); - /// Set role for the delayed node that spans exactly \p Range. - void markDelayedChild(llvm::ArrayRef Range, NodeRole R); - /// Set role for the node that may or may not be delayed. Node must span - /// exactly \p Range. - void markMaybeDelayedChild(llvm::ArrayRef Range, NodeRole R); /// Finish building the tree and consume the root node. syntax::TranslationUnit *finalize() && { @@ -285,7 +268,38 @@ class syntax::TreeBuilder { return maybeAppendSemicolon(Tokens, D); } - llvm::ArrayRef getDeclRange(const Decl *D) const { + /// Returns true if \p D is the last declarator in a chain and is thus + /// reponsible for creating SimpleDeclaration for the whole chain. + template + bool isResponsibleForCreatingDeclaration(const T *D) const { + static_assert((std::is_base_of::value || + std::is_base_of::value), + "only DeclaratorDecl and TypedefNameDecl are supported."); + + const Decl *Next = D->getNextDeclInContext(); + + // There's no next sibling, this one is responsible. + if (Next == nullptr) { + return true; + } + const auto *NextT = llvm::dyn_cast(Next); + + // Next sibling is not the same type, this one is responsible. + if (NextT == nullptr) { + return true; + } + // Next sibling doesn't begin at the same loc, it must be a different + // declaration, so this declarator is responsible. + if (NextT->getBeginLoc() != D->getBeginLoc()) { + return true; + } + + // NextT is a member of the same declaration, and we need the last member to + // create declaration. This one is not responsible. + return false; + } + + llvm::ArrayRef getDeclarationRange(Decl *D) { llvm::ArrayRef Tokens; // We want to drop the template parameters for specializations. if (const auto *S = llvm::dyn_cast(D)) @@ -294,9 +308,11 @@ class syntax::TreeBuilder { Tokens = getRange(D->getSourceRange()); return maybeAppendSemicolon(Tokens, D); } + llvm::ArrayRef getExprRange(const Expr *E) const { return getRange(E->getSourceRange()); } + /// Find the adjusted range for the statement, consuming the trailing /// semicolon when needed. llvm::ArrayRef getStmtRange(const Stmt *S) const { @@ -359,25 +375,6 @@ class syntax::TreeBuilder { } } - ~Forest() { assert(DelayedFolds.empty()); } - - void assignRoleDelayed(llvm::ArrayRef Range, - syntax::NodeRole Role) { - auto It = DelayedFolds.find(Range.begin()); - assert(It != DelayedFolds.end()); - assert(It->second.End == Range.end()); - It->second.Role = Role; - } - - void assignRoleMaybeDelayed(llvm::ArrayRef Range, - syntax::NodeRole Role) { - auto It = DelayedFolds.find(Range.begin()); - if (It == DelayedFolds.end()) - return assignRole(Range, Role); - assert(It->second.End == Range.end()); - It->second.Role = Role; - } - void assignRole(llvm::ArrayRef Range, syntax::NodeRole Role) { assert(!Range.empty()); @@ -396,50 +393,34 @@ class syntax::TreeBuilder { void foldChildren(const syntax::Arena &A, llvm::ArrayRef Tokens, syntax::Tree *Node) { - // Execute delayed folds inside `Tokens`. - auto BeginFolds = DelayedFolds.lower_bound(Tokens.begin()); - auto EndFolds = BeginFolds; - for (; EndFolds != DelayedFolds.end() && - EndFolds->second.End <= Tokens.end(); - ++EndFolds) - ; - // We go in reverse order to ensure we fold deeper nodes first. - for (auto RevIt = EndFolds; RevIt != BeginFolds; --RevIt) { - auto It = std::prev(RevIt); - foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End), - It->second.Node); - } - DelayedFolds.erase(BeginFolds, EndFolds); - // Attach children to `Node`. - foldChildrenEager(A, Tokens, Node); - } + assert(Node->firstChild() == nullptr && "node already has children"); - /// Schedule a call to `foldChildren` that will only be executed when - /// containing node is folded. The range of delayed nodes can be extended by - /// calling `extendDelayedFold`. Only one delayed node for each starting - /// token is allowed. - void foldChildrenDelayed(llvm::ArrayRef Tokens, - syntax::Tree *Node) { - assert(!Tokens.empty()); - bool Inserted = - DelayedFolds.insert({Tokens.begin(), DelayedFold{Tokens.end(), Node}}) - .second; - (void)Inserted; - assert(Inserted && "Multiple delayed folds start at the same token"); - } + auto *FirstToken = Tokens.begin(); + auto BeginChildren = Trees.lower_bound(FirstToken); - /// If there a delayed fold, starting at `ExtendedRange.begin()`, extends - /// its endpoint to `ExtendedRange.end()` and returns true. - /// Otherwise, returns false. - bool extendDelayedFold(llvm::ArrayRef ExtendedRange) { - assert(!ExtendedRange.empty()); - auto It = DelayedFolds.find(ExtendedRange.data()); - if (It == DelayedFolds.end()) - return false; - assert(It->second.End <= ExtendedRange.end()); - It->second.End = ExtendedRange.end(); - return true; + assert((BeginChildren == Trees.end() || + BeginChildren->first == FirstToken) && + "fold crosses boundaries of existing subtrees"); + auto EndChildren = Trees.lower_bound(Tokens.end()); + assert( + (EndChildren == Trees.end() || EndChildren->first == Tokens.end()) && + "fold crosses boundaries of existing subtrees"); + + // We need to go in reverse order, because we can only prepend. + for (auto It = EndChildren; It != BeginChildren; --It) { + auto *C = std::prev(It)->second; + if (C->role() == NodeRole::Detached) + C->setRole(NodeRole::Unknown); + Node->prependChildLowLevel(C); + } + + // Mark that this node came from the AST and is backed by the source code. + Node->Original = true; + Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue(); + + Trees.erase(BeginChildren, EndChildren); + Trees.insert({FirstToken, Node}); } // EXPECTS: all tokens were consumed and are owned by a single root node. @@ -467,51 +448,10 @@ class syntax::TreeBuilder { } private: - /// Implementation detail of `foldChildren`, does acutal folding ignoring - /// delayed folds. - void foldChildrenEager(const syntax::Arena &A, - llvm::ArrayRef Tokens, - syntax::Tree *Node) { - assert(Node->firstChild() == nullptr && "node already has children"); - - auto *FirstToken = Tokens.begin(); - auto BeginChildren = Trees.lower_bound(FirstToken); - assert((BeginChildren == Trees.end() || - BeginChildren->first == FirstToken) && - "fold crosses boundaries of existing subtrees"); - auto EndChildren = Trees.lower_bound(Tokens.end()); - assert( - (EndChildren == Trees.end() || EndChildren->first == Tokens.end()) && - "fold crosses boundaries of existing subtrees"); - - // We need to go in reverse order, because we can only prepend. - for (auto It = EndChildren; It != BeginChildren; --It) { - auto *C = std::prev(It)->second; - if (C->role() == NodeRole::Detached) - C->setRole(NodeRole::Unknown); - Node->prependChildLowLevel(C); - } - - // Mark that this node came from the AST and is backed by the source code. - Node->Original = true; - Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue(); - - Trees.erase(BeginChildren, EndChildren); - Trees.insert({FirstToken, Node}); - } - /// Maps from the start token to a subtree starting at that token. /// Keys in the map are pointers into the array of expanded tokens, so /// pointer order corresponds to the order of preprocessor tokens. std::map Trees; - - /// See documentation of `foldChildrenDelayed` for details. - struct DelayedFold { - const syntax::Token *End = nullptr; - syntax::Tree *Node = nullptr; - NodeRole Role = NodeRole::Unknown; - }; - std::map DelayedFolds; }; /// For debugging purposes. @@ -535,47 +475,16 @@ class BuildTreeVisitor : public RecursiveASTVisitor { bool shouldTraversePostOrder() const { return true; } bool WalkUpFromDeclaratorDecl(DeclaratorDecl *DD) { - // Ensure declarators are covered by SimpleDeclaration. - Builder.noticeDeclRange(Builder.getDeclRange(DD)); - - // Build the declarator node. - SourceRange Initializer; - if (auto *V = llvm::dyn_cast(DD)) { - auto *I = V->getInit(); - // Initializers in range-based-for are not part of the declarator - if (I && !V->isCXXForRangeDecl()) - Initializer = I->getSourceRange(); - } - auto Declarator = getDeclaratorRange( - Builder.sourceManager(), DD->getTypeSourceInfo()->getTypeLoc(), - getQualifiedNameStart(DD), Initializer); - if (Declarator.isValid()) { - auto *N = new (allocator()) syntax::SimpleDeclarator; - Builder.foldNode(Builder.getRange(Declarator), N, DD); - Builder.markChild(N, syntax::NodeRole::SimpleDeclaration_declarator); - } - - return true; + return processDeclaratorAndDeclaration(DD); } - bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) { - // Ensure declarators are covered by SimpleDeclaration. - Builder.noticeDeclRange(Builder.getDeclRange(D)); - - auto R = getDeclaratorRange( - Builder.sourceManager(), D->getTypeSourceInfo()->getTypeLoc(), - /*Name=*/D->getLocation(), /*Initializer=*/SourceRange()); - if (R.isValid()) { - auto *N = new (allocator()) syntax::SimpleDeclarator; - Builder.foldNode(Builder.getRange(R), N, D); - Builder.markChild(N, syntax::NodeRole::SimpleDeclaration_declarator); - } - return true; + bool WalkUpFromTypedefNameDecl(TypedefNameDecl *TD) { + return processDeclaratorAndDeclaration(TD); } bool VisitDecl(Decl *D) { assert(!D->isImplicit()); - Builder.foldNode(Builder.getDeclRange(D), + Builder.foldNode(Builder.getDeclarationRange(D), new (allocator()) syntax::UnknownDeclaration(), D); return true; } @@ -599,9 +508,9 @@ class BuildTreeVisitor : public RecursiveASTVisitor { bool WalkUpFromTemplateDecl(TemplateDecl *S) { foldTemplateDeclaration( - Builder.getDeclRange(S), + Builder.getDeclarationRange(S), Builder.findToken(S->getTemplateParameters()->getTemplateLoc()), - Builder.getDeclRange(S->getTemplatedDecl()), S); + Builder.getDeclarationRange(S->getTemplatedDecl()), S); return true; } @@ -618,7 +527,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor { syntax::Declaration *handleFreeStandingTagDecl(TagDecl *C) { assert(C->isFreeStanding()); // Class is a declaration specifier and needs a spanning declaration node. - auto DeclarationRange = Builder.getDeclRange(C); + auto DeclarationRange = Builder.getDeclarationRange(C); syntax::Declaration *Result = new (allocator()) syntax::SimpleDeclaration; Builder.foldNode(DeclarationRange, Result, nullptr); @@ -702,7 +611,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor { } bool WalkUpFromNamespaceDecl(NamespaceDecl *S) { - auto Tokens = Builder.getDeclRange(S); + auto Tokens = Builder.getDeclarationRange(S); if (Tokens.front().kind() == tok::coloncolon) { // Handle nested namespace definitions. Those start at '::' token, e.g. // namespace a^::b {} @@ -741,10 +650,9 @@ class BuildTreeVisitor : public RecursiveASTVisitor { bool WalkUpFromFunctionTypeLoc(FunctionTypeLoc L) { Builder.markChildToken(L.getLParenLoc(), syntax::NodeRole::OpenParen); - for (auto *P : L.getParams()) - Builder.markDelayedChild( - Builder.getDeclRange(P), - syntax::NodeRole::ParametersAndQualifiers_parameter); + for (auto *P : L.getParams()) { + Builder.markChild(P, syntax::NodeRole::ParametersAndQualifiers_parameter); + } Builder.markChildToken(L.getRParenLoc(), syntax::NodeRole::CloseParen); Builder.foldNode(Builder.getRange(L.getLParenLoc(), L.getEndLoc()), new (allocator()) syntax::ParametersAndQualifiers, L); @@ -755,7 +663,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor { if (!L.getTypePtr()->hasTrailingReturn()) return WalkUpFromFunctionTypeLoc(L); - auto TrailingReturnTokens = BuildTrailingReturn(L); + auto *TrailingReturnTokens = BuildTrailingReturn(L); // Finish building the node for parameters. Builder.markChild(TrailingReturnTokens, syntax::NodeRole::ParametersAndQualifiers_trailingReturn); @@ -877,7 +785,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor { } bool WalkUpFromEmptyDecl(EmptyDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::EmptyDeclaration, S); return true; } @@ -887,55 +795,108 @@ class BuildTreeVisitor : public RecursiveASTVisitor { syntax::NodeRole::StaticAssertDeclaration_condition); Builder.markExprChild(S->getMessage(), syntax::NodeRole::StaticAssertDeclaration_message); - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::StaticAssertDeclaration, S); return true; } bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::LinkageSpecificationDeclaration, S); return true; } bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::NamespaceAliasDefinition, S); return true; } bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::UsingNamespaceDirective, S); return true; } bool WalkUpFromUsingDecl(UsingDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::UsingDeclaration, S); return true; } bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::UsingDeclaration, S); return true; } bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::UsingDeclaration, S); return true; } bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) { - Builder.foldNode(Builder.getDeclRange(S), + Builder.foldNode(Builder.getDeclarationRange(S), new (allocator()) syntax::TypeAliasDeclaration, S); return true; } private: + template SourceLocation getQualifiedNameStart(T *D) { + static_assert((std::is_base_of::value || + std::is_base_of::value), + "only DeclaratorDecl and TypedefNameDecl are supported."); + + auto DN = D->getDeclName(); + bool IsAnonymous = DN.isIdentifier() && !DN.getAsIdentifierInfo(); + if (IsAnonymous) + return SourceLocation(); + + if (const auto *DD = llvm::dyn_cast(D)) { + if (DD->getQualifierLoc()) { + return DD->getQualifierLoc().getBeginLoc(); + } + } + + return D->getLocation(); + } + + SourceRange getInitializerRange(Decl *D) { + if (auto *V = llvm::dyn_cast(D)) { + auto *I = V->getInit(); + // Initializers in range-based-for are not part of the declarator + if (I && !V->isCXXForRangeDecl()) + return I->getSourceRange(); + } + + return SourceRange(); + } + + /// Folds SimpleDeclarator node (if present) and in case this is the last + /// declarator in the chain it also folds SimpleDeclaration node. + template bool processDeclaratorAndDeclaration(T *D) { + SourceRange Initializer = getInitializerRange(D); + auto Range = getDeclaratorRange(Builder.sourceManager(), + D->getTypeSourceInfo()->getTypeLoc(), + getQualifiedNameStart(D), Initializer); + + // There doesn't have to be a declarator (e.g. `void foo(int)` only has + // declaration, but no declarator). + if (Range.getBegin().isValid()) { + auto *N = new (allocator()) syntax::SimpleDeclarator; + Builder.foldNode(Builder.getRange(Range), N, nullptr); + Builder.markChild(N, syntax::NodeRole::SimpleDeclaration_declarator); + } + + if (Builder.isResponsibleForCreatingDeclaration(D)) { + Builder.foldNode(Builder.getDeclarationRange(D), + new (allocator()) syntax::SimpleDeclaration, D); + } + return true; + } + /// Returns the range of the built node. syntax::TrailingReturnType *BuildTrailingReturn(FunctionProtoTypeLoc L) { assert(L.getTypePtr()->hasTrailingReturn()); @@ -963,7 +924,7 @@ class BuildTreeVisitor : public RecursiveASTVisitor { Builder.markChild(ReturnDeclarator, syntax::NodeRole::TrailingReturnType_declarator); auto *R = new (allocator()) syntax::TrailingReturnType; - Builder.foldNode(Tokens, R, nullptr); + Builder.foldNode(Tokens, R, L); return R; } @@ -989,12 +950,10 @@ class BuildTreeVisitor : public RecursiveASTVisitor { ArrayRef TemplatedDeclaration, Decl *From) { assert(TemplateKW && TemplateKW->kind() == tok::kw_template); Builder.markChildToken(TemplateKW, syntax::NodeRole::IntroducerKeyword); - Builder.markMaybeDelayedChild( - TemplatedDeclaration, - syntax::NodeRole::TemplateDeclaration_declaration); auto *N = new (allocator()) syntax::TemplateDeclaration; Builder.foldNode(Range, N, From); + Builder.markChild(N, syntax::NodeRole::TemplateDeclaration_declaration); return N; } @@ -1006,13 +965,6 @@ class BuildTreeVisitor : public RecursiveASTVisitor { }; } // namespace -void syntax::TreeBuilder::noticeDeclRange(llvm::ArrayRef Range) { - if (Pending.extendDelayedFold(Range)) - return; - Pending.foldChildrenDelayed(Range, - new (allocator()) syntax::SimpleDeclaration); -} - void syntax::TreeBuilder::noticeDeclWithoutSemicolon(Decl *D) { DeclsWithoutSemicolons.insert(D); } @@ -1040,16 +992,6 @@ void syntax::TreeBuilder::markChild(ASTPtr N, NodeRole R) { setRole(SN, R); } -void syntax::TreeBuilder::markDelayedChild(llvm::ArrayRef Range, - NodeRole R) { - Pending.assignRoleDelayed(Range, R); -} - -void syntax::TreeBuilder::markMaybeDelayedChild( - llvm::ArrayRef Range, NodeRole R) { - Pending.assignRoleMaybeDelayed(Range, R); -} - void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { if (!Child) return; diff --git a/clang/lib/Tooling/Syntax/Tokens.cpp b/clang/lib/Tooling/Syntax/Tokens.cpp index 9e12d8b603bfe..af11f25b10581 100644 --- a/clang/lib/Tooling/Syntax/Tokens.cpp +++ b/clang/lib/Tooling/Syntax/Tokens.cpp @@ -35,6 +35,69 @@ using namespace clang; using namespace clang::syntax; +namespace { +// Finds the smallest consecutive subsuquence of Toks that covers R. +llvm::ArrayRef +getTokensCovering(llvm::ArrayRef Toks, SourceRange R, + const SourceManager &SM) { + if (R.isInvalid()) + return {}; + const syntax::Token *Begin = + llvm::partition_point(Toks, [&](const syntax::Token &T) { + return SM.isBeforeInTranslationUnit(T.location(), R.getBegin()); + }); + const syntax::Token *End = + llvm::partition_point(Toks, [&](const syntax::Token &T) { + return !SM.isBeforeInTranslationUnit(R.getEnd(), T.location()); + }); + if (Begin > End) + return {}; + return {Begin, End}; +} + +// Finds the smallest expansion range that contains expanded tokens First and +// Last, e.g.: +// #define ID(x) x +// ID(ID(ID(a1) a2)) +// ~~ -> a1 +// ~~ -> a2 +// ~~~~~~~~~ -> a1 a2 +SourceRange findCommonRangeForMacroArgs(const syntax::Token &First, + const syntax::Token &Last, + const SourceManager &SM) { + SourceRange Res; + auto FirstLoc = First.location(), LastLoc = Last.location(); + // Keep traversing up the spelling chain as longs as tokens are part of the + // same expansion. + while (!FirstLoc.isFileID() && !LastLoc.isFileID()) { + auto ExpInfoFirst = SM.getSLocEntry(SM.getFileID(FirstLoc)).getExpansion(); + auto ExpInfoLast = SM.getSLocEntry(SM.getFileID(LastLoc)).getExpansion(); + // Stop if expansions have diverged. + if (ExpInfoFirst.getExpansionLocStart() != + ExpInfoLast.getExpansionLocStart()) + break; + // Do not continue into macro bodies. + if (!ExpInfoFirst.isMacroArgExpansion() || + !ExpInfoLast.isMacroArgExpansion()) + break; + FirstLoc = SM.getImmediateSpellingLoc(FirstLoc); + LastLoc = SM.getImmediateSpellingLoc(LastLoc); + // Update the result afterwards, as we want the tokens that triggered the + // expansion. + Res = {FirstLoc, LastLoc}; + } + // Normally mapping back to expansion location here only changes FileID, as + // we've already found some tokens expanded from the same macro argument, and + // they should map to a consecutive subset of spelled tokens. Unfortunately + // SourceManager::isBeforeInTranslationUnit discriminates sourcelocations + // based on their FileID in addition to offsets. So even though we are + // referring to same tokens, SourceManager might tell us that one is before + // the other if they've got different FileIDs. + return SM.getExpansionRange(CharSourceRange(Res, true)).getAsRange(); +} + +} // namespace + syntax::Token::Token(SourceLocation Location, unsigned Length, tok::TokenKind Kind) : Location(Location), Length(Length), Kind(Kind) { @@ -121,19 +184,7 @@ llvm::StringRef FileRange::text(const SourceManager &SM) const { } llvm::ArrayRef TokenBuffer::expandedTokens(SourceRange R) const { - if (R.isInvalid()) - return {}; - const Token *Begin = - llvm::partition_point(expandedTokens(), [&](const syntax::Token &T) { - return SourceMgr->isBeforeInTranslationUnit(T.location(), R.getBegin()); - }); - const Token *End = - llvm::partition_point(expandedTokens(), [&](const syntax::Token &T) { - return !SourceMgr->isBeforeInTranslationUnit(R.getEnd(), T.location()); - }); - if (Begin > End) - return {}; - return {Begin, End}; + return getTokensCovering(expandedTokens(), R, *SourceMgr); } CharSourceRange FileRange::toCharRange(const SourceManager &SM) const { @@ -206,8 +257,6 @@ TokenBuffer::spelledForExpanded(llvm::ArrayRef Expanded) const { if (Expanded.empty()) return llvm::None; - // FIXME: also allow changes uniquely mapping to macro arguments. - const syntax::Token *BeginSpelled; const Mapping *BeginMapping; std::tie(BeginSpelled, BeginMapping) = @@ -225,12 +274,28 @@ TokenBuffer::spelledForExpanded(llvm::ArrayRef Expanded) const { const MarkedFile &File = Files.find(FID)->second; - // Do not allow changes that cross macro expansion boundaries. + // If both tokens are coming from a macro argument expansion, try and map to + // smallest part of the macro argument. BeginMapping && LastMapping check is + // only for performance, they are a prerequisite for Expanded.front() and + // Expanded.back() being part of a macro arg expansion. + if (BeginMapping && LastMapping && + SourceMgr->isMacroArgExpansion(Expanded.front().location()) && + SourceMgr->isMacroArgExpansion(Expanded.back().location())) { + auto CommonRange = findCommonRangeForMacroArgs(Expanded.front(), + Expanded.back(), *SourceMgr); + // It might be the case that tokens are arguments of different macro calls, + // in that case we should continue with the logic below instead of returning + // an empty range. + if (CommonRange.isValid()) + return getTokensCovering(File.SpelledTokens, CommonRange, *SourceMgr); + } + + // Do not allow changes that doesn't cover full expansion. unsigned BeginExpanded = Expanded.begin() - ExpandedTokens.data(); unsigned EndExpanded = Expanded.end() - ExpandedTokens.data(); - if (BeginMapping && BeginMapping->BeginExpanded < BeginExpanded) + if (BeginMapping && BeginExpanded != BeginMapping->BeginExpanded) return llvm::None; - if (LastMapping && EndExpanded < LastMapping->EndExpanded) + if (LastMapping && LastMapping->EndExpanded != EndExpanded) return llvm::None; // All is good, return the result. return llvm::makeArrayRef( @@ -645,8 +710,8 @@ std::string syntax::Token::str() const { } std::string syntax::Token::dumpForTests(const SourceManager &SM) const { - return std::string( - llvm::formatv("{0} {1}", tok::getTokenName(kind()), text(SM))); + return std::string(llvm::formatv("Token(`{0}`, {1}, length = {2})", text(SM), + tok::getTokenName(kind()), length())); } std::string TokenBuffer::dumpForTests() const { diff --git a/clang/lib/Tooling/Transformer/SourceCode.cpp b/clang/lib/Tooling/Transformer/SourceCode.cpp index 38b331b0a1c3b..0530b3fa0e959 100644 --- a/clang/lib/Tooling/Transformer/SourceCode.cpp +++ b/clang/lib/Tooling/Transformer/SourceCode.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/Errc.h" +#include using namespace clang; diff --git a/clang/test/AST/ast-dump-expr-errors.cpp b/clang/test/AST/ast-dump-expr-errors.cpp index e623fad04f4c8..9334b73a43545 100644 --- a/clang/test/AST/ast-dump-expr-errors.cpp +++ b/clang/test/AST/ast-dump-expr-errors.cpp @@ -42,5 +42,9 @@ int d = static_cast(bar() + 1); // FIXME: store initializer even when 'auto' could not be deduced. // Expressions with errors currently do not keep initializers around. -// CHECK: `-VarDecl {{.*}} invalid e 'auto' +// CHECK: -VarDecl {{.*}} invalid e 'auto' auto e = bar(); + +// Error type should result in an invalid decl. +// CHECK: -VarDecl {{.*}} invalid f 'decltype((bar))' +decltype(bar()) f; diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_1.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_1.c new file mode 100644 index 0000000000000..f427049807c61 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_1.c @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics + +int also_before(void) { + return 0; +} + +#pragma omp begin declare variant match(device={kind(gpu)}) +int also_after(void) { + return 1; +} +int also_before(void) { + return 2; +} +#pragma omp end declare variant + + +#pragma omp begin declare variant match(device={kind(fpga)}) + +This text is never parsed! + +#pragma omp end declare variant + +int also_after(void) { + return 0; +} + +int test() { + // Should return 0. + return also_after() + also_before(); +} + +// Make sure: +// - we do not see the ast nodes for the gpu kind +// - we do not choke on the text in the kind(fpga) guarded scopes + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] line:25:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_5:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_6:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_7:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: `-FunctionDecl [[ADDR_8:0x[a-z0-9]*]] line:29:5 test 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_9:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_10:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_11:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-CallExpr [[ADDR_12:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_13:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_14:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_4]] 'also_after' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_15:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_16:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_17:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_0]] 'also_before' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_2.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_2.c new file mode 100644 index 0000000000000..fda973b1e6c4c --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_2.c @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics + +#pragma omp begin declare variant match(device={kind(cpu)}) +int also_before(void) { + return 0; +} +#pragma omp end declare variant + +#pragma omp begin declare variant match(implementation={vendor(score(100):llvm)}) +int also_after(void) { + return 0; +} +#pragma omp end declare variant +#pragma omp begin declare variant match(implementation={vendor(score(0):llvm)}) +int also_before(void) { + return 1; +} +#pragma omp end declare variant + +int also_after(void) { + return 2; +} + +int test() { + // Should return 0. + return also_after() + also_before(); +} + +// Make sure: +// - we do see the ast nodes for the cpu kind +// - we do see the ast nodes for the llvm vendor +// - we pick the right callees + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, col:21> col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_1:0x[a-z0-9]*]] <> Implicit device={kind(cpu)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_2:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_3:0x[a-z0-9]*]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_3]] line:6:1 also_before[device={kind(cpu)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_4:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_5:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_6:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_7:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_8:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_10:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_10]] line:12:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_11:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_12:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_13:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_14:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | |-OMPDeclareVariantAttr [[ADDR_15:0x[a-z0-9]*]] <> Inherited Implicit device={kind(cpu)} +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_2]] 'int ({{.*}})' Function [[ADDR_3]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_16:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(0): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_17:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_18]] line:17:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_22:0x[a-z0-9]*]] prev [[ADDR_7]] line:22:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_23:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_24:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-IntegerLiteral [[ADDR_25:0x[a-z0-9]*]] 'int' 2 +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_26:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9]] 'int ({{.*}})' Function [[ADDR_10]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: `-FunctionDecl [[ADDR_27:0x[a-z0-9]*]] line:26:5 test 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_28:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_29:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_30:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-PseudoObjectExpr [[ADDR_31:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-CallExpr [[ADDR_32:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | `-ImplicitCastExpr [[ADDR_33:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_34:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_22]] 'also_after' 'int ({{.*}})' +// CHECK-NEXT: | `-CallExpr [[ADDR_35:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_36:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9]] 'int ({{.*}})' Function [[ADDR_10]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: `-PseudoObjectExpr [[ADDR_37:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: |-CallExpr [[ADDR_38:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_39:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_40:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_14]] 'also_before' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_41:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_2]] 'int ({{.*}})' Function [[ADDR_3]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_3.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_3.c new file mode 100644 index 0000000000000..efedd2f9bb746 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_3.c @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics + +#pragma omp begin declare variant match(device={kind(cpu)}) +int also_before(void) { + return 1; +} +#pragma omp end declare variant + +#pragma omp begin declare variant match(implementation={vendor(score(0):llvm)}) +int also_after(void) { + return 0; +} +#pragma omp end declare variant +#pragma omp begin declare variant match(implementation={vendor(score(100):llvm)}) +int also_before(void) { + return 0; +} +#pragma omp end declare variant + +int also_after(void) { + return 2; +} + +int test() { + // Should return 0. + return also_after() + also_before(); +} + +// Make sure: +// - we do see the ast nodes for the cpu kind +// - we do see the ast nodes for the llvm vendor +// - we pick the right callees + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, col:21> col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_1:0x[a-z0-9]*]] <> Implicit device={kind(cpu)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_2:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_3:0x[a-z0-9]*]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_3]] line:6:1 also_before[device={kind(cpu)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_4:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_5:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_6:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_7:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_8:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(0): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_10:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_10]] line:12:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_11:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_12:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_13:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_14:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | |-OMPDeclareVariantAttr [[ADDR_15:0x[a-z0-9]*]] <> Inherited Implicit device={kind(cpu)} +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_2]] 'int ({{.*}})' Function [[ADDR_3]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_16:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_17:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_18]] line:17:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_22:0x[a-z0-9]*]] prev [[ADDR_7]] line:22:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_23:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_24:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-IntegerLiteral [[ADDR_25:0x[a-z0-9]*]] 'int' 2 +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_26:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(score(0): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9]] 'int ({{.*}})' Function [[ADDR_10]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: `-FunctionDecl [[ADDR_27:0x[a-z0-9]*]] line:26:5 test 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_28:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_29:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_30:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-PseudoObjectExpr [[ADDR_31:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-CallExpr [[ADDR_32:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | `-ImplicitCastExpr [[ADDR_33:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_34:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_22]] 'also_after' 'int ({{.*}})' +// CHECK-NEXT: | `-CallExpr [[ADDR_35:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_36:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9]] 'int ({{.*}})' Function [[ADDR_10]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: `-PseudoObjectExpr [[ADDR_37:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: |-CallExpr [[ADDR_38:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_39:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_40:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_14]] 'also_before' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_41:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_17]] 'int ({{.*}})' Function [[ADDR_18]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_4.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_4.c new file mode 100644 index 0000000000000..b35433478e49b --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_4.c @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics + +#pragma omp begin declare variant match(device={kind(cpu)}) +int also_before(void) { + return 0; +} +#pragma omp end declare variant + +int also_after(void) { + return 0; +} + +int test() { + // Should return 0. + return also_after() + also_before(); +} + +// Make sure: +// - we do see the ast nodes for the cpu kind +// - we pick the right callees + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, col:21> col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_1:0x[a-z0-9]*]] <> Implicit device={kind(cpu)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_2:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_3:0x[a-z0-9]*]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_3]] line:6:1 also_before[device={kind(cpu)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_4:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_5:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_6:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_7:0x[a-z0-9]*]] line:11:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: `-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] line:15:5 test 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_12:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_13:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_14:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-CallExpr [[ADDR_15:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_16:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_17:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_7]] 'also_after' 'int ({{.*}})' +// CHECK-NEXT: `-PseudoObjectExpr [[ADDR_18:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: |-CallExpr [[ADDR_19:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_20:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_21:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_0]] 'also_before' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_22:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_23:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_2]] 'int ({{.*}})' Function [[ADDR_3]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_5.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_5.c new file mode 100644 index 0000000000000..b2a1cb0b3c86a --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_5.c @@ -0,0 +1,158 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s --check-prefix=C +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s --check-prefix=CXX +// expected-no-diagnostics + +int also_before(void) { + return 1; +} + +#pragma omp begin declare variant match(implementation={vendor(llvm)}) +int also_after(void) { + return 0; +} +int also_before(void) { + return 0; +} +#pragma omp end declare variant + +int also_after(void) { + return 2; +} + +int main() { + // Should return 0. + return (also_after)() + + (also_before)() + + (&also_after)() + + (&also_before)(); +} + +// Make sure: +// - we see the specialization in the AST +// - we pick the right callees + +// C: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 1 +// C-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_5:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_6:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_7:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_7]] line:10:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: |-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_12:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_13:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_14:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_14]] line:13:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_15:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_16:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_17:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: |-FunctionDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_4]] line:18:5 used also_after 'int ({{.*}})' +// C-NEXT: | |-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// C-NEXT: | | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// C-NEXT: | | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 2 +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_22:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: `-FunctionDecl [[ADDR_23:0x[a-z0-9]*]] line:22:5 main 'int ({{.*}})' +// C-NEXT: `-CompoundStmt [[ADDR_24:0x[a-z0-9]*]] +// C-NEXT: `-ReturnStmt [[ADDR_25:0x[a-z0-9]*]] +// C-NEXT: `-BinaryOperator [[ADDR_26:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: |-BinaryOperator [[ADDR_27:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: | |-BinaryOperator [[ADDR_28:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: | | |-PseudoObjectExpr [[ADDR_29:0x[a-z0-9]*]] 'int' +// C-NEXT: | | | |-CallExpr [[ADDR_30:0x[a-z0-9]*]] 'int' +// C-NEXT: | | | | `-ImplicitCastExpr [[ADDR_31:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | | | `-ParenExpr [[ADDR_32:0x[a-z0-9]*]] 'int ({{.*}})' +// C-NEXT: | | | | `-DeclRefExpr [[ADDR_33:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// C-NEXT: | | | `-CallExpr [[ADDR_34:0x[a-z0-9]*]] 'int' +// C-NEXT: | | | `-ImplicitCastExpr [[ADDR_35:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: | | `-PseudoObjectExpr [[ADDR_36:0x[a-z0-9]*]] 'int' +// C-NEXT: | | |-CallExpr [[ADDR_37:0x[a-z0-9]*]] 'int' +// C-NEXT: | | | `-ImplicitCastExpr [[ADDR_38:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | | `-ParenExpr [[ADDR_39:0x[a-z0-9]*]] 'int ({{.*}})' +// C-NEXT: | | | `-DeclRefExpr [[ADDR_40:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// C-NEXT: | | `-CallExpr [[ADDR_41:0x[a-z0-9]*]] 'int' +// C-NEXT: | | `-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | `-DeclRefExpr [[ADDR_13]] 'int ({{.*}})' Function [[ADDR_14]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: | `-PseudoObjectExpr [[ADDR_43:0x[a-z0-9]*]] 'int' +// C-NEXT: | |-CallExpr [[ADDR_44:0x[a-z0-9]*]] 'int' +// C-NEXT: | | `-ParenExpr [[ADDR_45:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | `-UnaryOperator [[ADDR_46:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// C-NEXT: | | `-DeclRefExpr [[ADDR_47:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// C-NEXT: | `-CallExpr [[ADDR_48:0x[a-z0-9]*]] 'int' +// C-NEXT: | `-ImplicitCastExpr [[ADDR_49:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: `-PseudoObjectExpr [[ADDR_50:0x[a-z0-9]*]] 'int' +// C-NEXT: |-CallExpr [[ADDR_51:0x[a-z0-9]*]] 'int' +// C-NEXT: | `-ParenExpr [[ADDR_52:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | `-UnaryOperator [[ADDR_53:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// C-NEXT: | `-DeclRefExpr [[ADDR_54:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// C-NEXT: `-CallExpr [[ADDR_55:0x[a-z0-9]*]] 'int' +// C-NEXT: `-ImplicitCastExpr [[ADDR_56:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: `-DeclRefExpr [[ADDR_13]] 'int ({{.*}})' Function [[ADDR_14]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' + +// CXX: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 1 +// CXX-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_5:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_6:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_7:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_7]] line:10:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: |-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_12:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_13:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_14:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_14]] line:13:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_15:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_16:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_17:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: |-FunctionDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_4]] line:18:5 used also_after 'int ({{.*}})' +// CXX-NEXT: | |-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CXX-NEXT: | | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CXX-NEXT: | | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 2 +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_22:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: `-FunctionDecl [[ADDR_23:0x[a-z0-9]*]] line:22:5 main 'int ({{.*}})' +// CXX-NEXT: `-CompoundStmt [[ADDR_24:0x[a-z0-9]*]] +// CXX-NEXT: `-ReturnStmt [[ADDR_25:0x[a-z0-9]*]] +// CXX-NEXT: `-BinaryOperator [[ADDR_26:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: |-BinaryOperator [[ADDR_27:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: | |-BinaryOperator [[ADDR_28:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: | | |-PseudoObjectExpr [[ADDR_29:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | | |-CallExpr [[ADDR_30:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | | | `-ImplicitCastExpr [[ADDR_31:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | | | `-ParenExpr [[ADDR_32:0x[a-z0-9]*]] 'int ({{.*}})' lvalue +// CXX-NEXT: | | | | `-DeclRefExpr [[ADDR_33:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// CXX-NEXT: | | | `-CallExpr [[ADDR_34:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | | `-ImplicitCastExpr [[ADDR_35:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: | | `-PseudoObjectExpr [[ADDR_36:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | |-CallExpr [[ADDR_37:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | | `-ImplicitCastExpr [[ADDR_38:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | | `-ParenExpr [[ADDR_39:0x[a-z0-9]*]] 'int ({{.*}})' lvalue +// CXX-NEXT: | | | `-DeclRefExpr [[ADDR_40:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// CXX-NEXT: | | `-CallExpr [[ADDR_41:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | `-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | `-DeclRefExpr [[ADDR_13]] 'int ({{.*}})' Function [[ADDR_14]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: | `-PseudoObjectExpr [[ADDR_43:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | |-CallExpr [[ADDR_44:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | `-ParenExpr [[ADDR_45:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | `-UnaryOperator [[ADDR_46:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// CXX-NEXT: | | `-DeclRefExpr [[ADDR_47:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// CXX-NEXT: | `-CallExpr [[ADDR_48:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | `-ImplicitCastExpr [[ADDR_49:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: `-PseudoObjectExpr [[ADDR_50:0x[a-z0-9]*]] 'int' +// CXX-NEXT: |-CallExpr [[ADDR_51:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | `-ParenExpr [[ADDR_52:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | `-UnaryOperator [[ADDR_53:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// CXX-NEXT: | `-DeclRefExpr [[ADDR_54:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// CXX-NEXT: `-CallExpr [[ADDR_55:0x[a-z0-9]*]] 'int' +// CXX-NEXT: `-ImplicitCastExpr [[ADDR_56:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: `-DeclRefExpr [[ADDR_13]] 'int ({{.*}})' Function [[ADDR_14]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_6.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_6.c new file mode 100644 index 0000000000000..1e5241bc2c589 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_6.c @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics + +int also_before(void) { + return 0; +} + +#pragma omp begin declare variant match(implementation={vendor(ibm)}) +int also_after(void) { + return 1; +} +int also_before(void) { + return 2; +} +#pragma omp end declare variant + +int also_after(void) { + return 0; +} + +int main() { + // Should return 0. + return also_after() + also_before(); +} + +// Make sure: +// - we see the specialization in the AST +// - we do use the original pointers for the calls as the variants are not applicable (this is not the ibm compiler). + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_5:0x[a-z0-9]*]] <> Implicit implementation={vendor(ibm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_6:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_7:0x[a-z0-9]*]] 'also_after[implementation={vendor(ibm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_7]] line:10:1 also_after[implementation={vendor(ibm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_12:0x[a-z0-9]*]] <> Implicit implementation={vendor(ibm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_13:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_14:0x[a-z0-9]*]] 'also_before[implementation={vendor(ibm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_14]] line:13:1 also_before[implementation={vendor(ibm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_15:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_16:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_17:0x[a-z0-9]*]] 'int' 2 +// CHECK-NEXT: |-FunctionDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_4]] line:18:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_22:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(ibm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(ibm)}]' 'int ({{.*}})' +// CHECK-NEXT: `-FunctionDecl [[ADDR_23:0x[a-z0-9]*]] line:22:5 main 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_24:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_25:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_26:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-CallExpr [[ADDR_27:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_28:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_29:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_30:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_31:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_32:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_11]] 'also_before' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_7.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_7.c new file mode 100644 index 0000000000000..cf5c1f3f62c13 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_7.c @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics + +int OK_1(void); + +#pragma omp begin declare variant match(implementation={vendor(intel)}) +int OK_1(void) { + return 1; +} +int OK_2(void) { + return 1; +} +int not_OK(void) { + return 1; +} +int OK_3(void) { + return 1; +} +#pragma omp end declare variant + +int OK_3(void); + +int test() { + // Should cause an error due to not_OK() + return OK_1() + not_OK() + OK_3(); +} + +// Make sure: +// - we see a single error for `not_OK` +// - we do not see errors for OK_{1,2,3} +// FIXME: We actually do not see there error here. +// This case is unlikely to happen in practise and hard to diagnose during SEMA. +// We will issue an error during code generation instead. This is similar to the +// diagnosis in other multi-versioning schemes. + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, col:14> col:5 used OK_1 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_1:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used OK_1 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_2:0x[a-z0-9]*]] <> Implicit implementation={vendor(intel)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_3:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_4:0x[a-z0-9]*]] 'OK_1[implementation={vendor(intel)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_4]] line:8:1 OK_1[implementation={vendor(intel)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_5:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_6:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_7:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_8:0x[a-z0-9]*]] col:5 implicit OK_2 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_9:0x[a-z0-9]*]] <> Implicit implementation={vendor(intel)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_10:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_11:0x[a-z0-9]*]] 'OK_2[implementation={vendor(intel)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_11]] line:11:1 OK_2[implementation={vendor(intel)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_12:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_13:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_14:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_15:0x[a-z0-9]*]] col:5 implicit used not_OK 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_16:0x[a-z0-9]*]] <> Implicit implementation={vendor(intel)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_17:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18:0x[a-z0-9]*]] 'not_OK[implementation={vendor(intel)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_18]] line:14:1 not_OK[implementation={vendor(intel)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_22:0x[a-z0-9]*]] col:5 implicit used OK_3 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_23:0x[a-z0-9]*]] <> Implicit implementation={vendor(intel)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_24:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_25:0x[a-z0-9]*]] 'OK_3[implementation={vendor(intel)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_25]] line:17:1 OK_3[implementation={vendor(intel)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_26:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_27:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_28:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_29:0x[a-z0-9]*]] prev [[ADDR_22]] col:5 used OK_3 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_30:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(intel)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_24]] 'int ({{.*}})' Function [[ADDR_25]] 'OK_3[implementation={vendor(intel)}]' 'int ({{.*}})' +// CHECK-NEXT: `-FunctionDecl [[ADDR_31:0x[a-z0-9]*]] line:24:5 test 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_32:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_33:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_34:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-BinaryOperator [[ADDR_35:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: | |-CallExpr [[ADDR_36:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | `-ImplicitCastExpr [[ADDR_37:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_38:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_1]] 'OK_1' 'int ({{.*}})' +// CHECK-NEXT: | `-CallExpr [[ADDR_39:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_40:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_41:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_15]] 'not_OK' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_42:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_43:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_44:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_29]] 'OK_3' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_8.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_8.c new file mode 100644 index 0000000000000..efedd2f9bb746 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_8.c @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics + +#pragma omp begin declare variant match(device={kind(cpu)}) +int also_before(void) { + return 1; +} +#pragma omp end declare variant + +#pragma omp begin declare variant match(implementation={vendor(score(0):llvm)}) +int also_after(void) { + return 0; +} +#pragma omp end declare variant +#pragma omp begin declare variant match(implementation={vendor(score(100):llvm)}) +int also_before(void) { + return 0; +} +#pragma omp end declare variant + +int also_after(void) { + return 2; +} + +int test() { + // Should return 0. + return also_after() + also_before(); +} + +// Make sure: +// - we do see the ast nodes for the cpu kind +// - we do see the ast nodes for the llvm vendor +// - we pick the right callees + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, col:21> col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_1:0x[a-z0-9]*]] <> Implicit device={kind(cpu)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_2:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_3:0x[a-z0-9]*]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_3]] line:6:1 also_before[device={kind(cpu)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_4:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_5:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_6:0x[a-z0-9]*]] 'int' 1 +// CHECK-NEXT: |-FunctionDecl [[ADDR_7:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_8:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(0): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_10:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_10]] line:12:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_11:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_12:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_13:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_14:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// CHECK-NEXT: | |-OMPDeclareVariantAttr [[ADDR_15:0x[a-z0-9]*]] <> Inherited Implicit device={kind(cpu)} +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_2]] 'int ({{.*}})' Function [[ADDR_3]] 'also_before[device={kind(cpu)}]' 'int ({{.*}})' +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_16:0x[a-z0-9]*]] <> Implicit implementation={vendor(score(100): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_17:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_18]] line:17:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_22:0x[a-z0-9]*]] prev [[ADDR_7]] line:22:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: | |-CompoundStmt [[ADDR_23:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-ReturnStmt [[ADDR_24:0x[a-z0-9]*]] +// CHECK-NEXT: | | `-IntegerLiteral [[ADDR_25:0x[a-z0-9]*]] 'int' 2 +// CHECK-NEXT: | `-OMPDeclareVariantAttr [[ADDR_26:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(score(0): llvm)} +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9]] 'int ({{.*}})' Function [[ADDR_10]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: `-FunctionDecl [[ADDR_27:0x[a-z0-9]*]] line:26:5 test 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_28:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_29:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_30:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-PseudoObjectExpr [[ADDR_31:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | |-CallExpr [[ADDR_32:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | | `-ImplicitCastExpr [[ADDR_33:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | | `-DeclRefExpr [[ADDR_34:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_22]] 'also_after' 'int ({{.*}})' +// CHECK-NEXT: | `-CallExpr [[ADDR_35:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_36:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_9]] 'int ({{.*}})' Function [[ADDR_10]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CHECK-NEXT: `-PseudoObjectExpr [[ADDR_37:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: |-CallExpr [[ADDR_38:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_39:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_40:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_14]] 'also_before' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_41:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_17]] 'int ({{.*}})' Function [[ADDR_18]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_9.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_9.c new file mode 100644 index 0000000000000..af61859ae3068 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_9.c @@ -0,0 +1,184 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s --check-prefix=C +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s --check-prefix=CXX +// expected-no-diagnostics + +int also_before(void) { + return 0; +} + +#pragma omp begin declare variant match(implementation={vendor(llvm)}) +int also_after(void) { + return 1; +} +int also_before(void) { + return 2; +} +#pragma omp end declare variant + +int also_after(void) { + return 0; +} + +void foo(); +typedef int(*fd)(void); +int main() { + // Should return 0. + fd fns[2]; + fns[0] = &also_before; + fns[1] = also_after; + return (foo(), also_after)() + + (fns[0])() + + (1[fns])(); +} + +// Make sure: +// - we see the specialization in the AST +// - we pick the right callees + +// C: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_5:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_6:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_7:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_7]] line:10:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 1 +// C-NEXT: |-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_12:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_13:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_14:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_14]] line:13:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_15:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_16:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_17:0x[a-z0-9]*]] 'int' 2 +// C-NEXT: |-FunctionDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_4]] line:18:5 used also_after 'int ({{.*}})' +// C-NEXT: | |-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// C-NEXT: | | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// C-NEXT: | | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_22:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_23:0x[a-z0-9]*]] col:6 used foo 'void ({{.*}})' +// C-NEXT: |-TypedefDecl [[ADDR_24:0x[a-z0-9]*]] col:14 referenced fd 'int (*)({{.*}})' +// C-NEXT: | `-PointerType [[ADDR_25:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | `-ParenType [[ADDR_26:0x[a-z0-9]*]] 'int ({{.*}})' sugar +// C-NEXT: | `-FunctionProtoType [[ADDR_27:0x[a-z0-9]*]] 'int ({{.*}})' cdecl +// C-NEXT: | `-BuiltinType [[ADDR_28:0x[a-z0-9]*]] 'int' +// C-NEXT: `-FunctionDecl [[ADDR_29:0x[a-z0-9]*]] line:24:5 main 'int ({{.*}})' +// C-NEXT: `-CompoundStmt [[ADDR_30:0x[a-z0-9]*]] +// C-NEXT: |-DeclStmt [[ADDR_31:0x[a-z0-9]*]] +// C-NEXT: | `-VarDecl [[ADDR_32:0x[a-z0-9]*]] col:6 used fns 'fd [2]' +// C-NEXT: |-BinaryOperator [[ADDR_33:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' '=' +// C-NEXT: | |-ArraySubscriptExpr [[ADDR_34:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// C-NEXT: | | |-ImplicitCastExpr [[ADDR_35:0x[a-z0-9]*]] 'fd *' +// C-NEXT: | | | `-DeclRefExpr [[ADDR_36:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' +// C-NEXT: | | `-IntegerLiteral [[ADDR_37:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: | `-UnaryOperator [[ADDR_38:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// C-NEXT: | `-DeclRefExpr [[ADDR_39:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// C-NEXT: |-BinaryOperator [[ADDR_40:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' '=' +// C-NEXT: | |-ArraySubscriptExpr [[ADDR_41:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// C-NEXT: | | |-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'fd *' +// C-NEXT: | | | `-DeclRefExpr [[ADDR_43:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' +// C-NEXT: | | `-IntegerLiteral [[ADDR_44:0x[a-z0-9]*]] 'int' 1 +// C-NEXT: | `-ImplicitCastExpr [[ADDR_45:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | `-DeclRefExpr [[ADDR_46:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// C-NEXT: `-ReturnStmt [[ADDR_47:0x[a-z0-9]*]] +// C-NEXT: `-BinaryOperator [[ADDR_48:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: |-BinaryOperator [[ADDR_49:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: | |-CallExpr [[ADDR_50:0x[a-z0-9]*]] 'int' +// C-NEXT: | | `-ParenExpr [[ADDR_51:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | `-BinaryOperator [[ADDR_52:0x[a-z0-9]*]] 'int (*)({{.*}})' ',' +// C-NEXT: | | |-CallExpr [[ADDR_53:0x[a-z0-9]*]] 'void' +// C-NEXT: | | | `-ImplicitCastExpr [[ADDR_54:0x[a-z0-9]*]] 'void (*)({{.*}})' +// C-NEXT: | | | `-DeclRefExpr [[ADDR_55:0x[a-z0-9]*]] 'void ({{.*}})' Function [[ADDR_23]] 'foo' 'void ({{.*}})' +// C-NEXT: | | `-ImplicitCastExpr [[ADDR_56:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | `-DeclRefExpr [[ADDR_57:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// C-NEXT: | `-CallExpr [[ADDR_58:0x[a-z0-9]*]] 'int' +// C-NEXT: | `-ImplicitCastExpr [[ADDR_59:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' +// C-NEXT: | `-ParenExpr [[ADDR_60:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// C-NEXT: | `-ArraySubscriptExpr [[ADDR_61:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// C-NEXT: | |-ImplicitCastExpr [[ADDR_62:0x[a-z0-9]*]] 'fd *' +// C-NEXT: | | `-DeclRefExpr [[ADDR_63:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' +// C-NEXT: | `-IntegerLiteral [[ADDR_64:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: `-CallExpr [[ADDR_65:0x[a-z0-9]*]] 'int' +// C-NEXT: `-ImplicitCastExpr [[ADDR_66:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' +// C-NEXT: `-ParenExpr [[ADDR_67:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// C-NEXT: `-ArraySubscriptExpr [[ADDR_68:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// C-NEXT: |-IntegerLiteral [[ADDR_69:0x[a-z0-9]*]] 'int' 1 +// C-NEXT: `-ImplicitCastExpr [[ADDR_70:0x[a-z0-9]*]] 'fd *' +// C-NEXT: `-DeclRefExpr [[ADDR_71:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' + +// CXX: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_5:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_6:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_7:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_7]] line:10:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 1 +// CXX-NEXT: |-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_12:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_13:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_14:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_14]] line:13:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_15:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_16:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_17:0x[a-z0-9]*]] 'int' 2 +// CXX-NEXT: |-FunctionDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_4]] line:18:5 used also_after 'int ({{.*}})' +// CXX-NEXT: | |-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CXX-NEXT: | | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CXX-NEXT: | | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_22:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_23:0x[a-z0-9]*]] col:6 used foo 'void ({{.*}})' +// CXX-NEXT: |-TypedefDecl [[ADDR_24:0x[a-z0-9]*]] col:14 referenced fd 'int (*)({{.*}})' +// CXX-NEXT: | `-PointerType [[ADDR_25:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | `-ParenType [[ADDR_26:0x[a-z0-9]*]] 'int ({{.*}})' sugar +// CXX-NEXT: | `-FunctionProtoType [[ADDR_27:0x[a-z0-9]*]] 'int ({{.*}})' cdecl +// CXX-NEXT: | `-BuiltinType [[ADDR_28:0x[a-z0-9]*]] 'int' +// CXX-NEXT: `-FunctionDecl [[ADDR_29:0x[a-z0-9]*]] line:24:5 main 'int ({{.*}})' +// CXX-NEXT: `-CompoundStmt [[ADDR_30:0x[a-z0-9]*]] +// CXX-NEXT: |-DeclStmt [[ADDR_31:0x[a-z0-9]*]] +// CXX-NEXT: | `-VarDecl [[ADDR_32:0x[a-z0-9]*]] col:6 used fns 'fd [2]' +// CXX-NEXT: |-BinaryOperator [[ADDR_33:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' {{.*}}'=' +// CXX-NEXT: | |-ArraySubscriptExpr [[ADDR_34:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// CXX-NEXT: | | |-ImplicitCastExpr [[ADDR_35:0x[a-z0-9]*]] 'fd *' +// CXX-NEXT: | | | `-DeclRefExpr [[ADDR_36:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' +// CXX-NEXT: | | `-IntegerLiteral [[ADDR_37:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: | `-UnaryOperator [[ADDR_38:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// CXX-NEXT: | `-DeclRefExpr [[ADDR_39:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// CXX-NEXT: |-BinaryOperator [[ADDR_40:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' {{.*}}'=' +// CXX-NEXT: | |-ArraySubscriptExpr [[ADDR_41:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// CXX-NEXT: | | |-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'fd *' +// CXX-NEXT: | | | `-DeclRefExpr [[ADDR_43:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' +// CXX-NEXT: | | `-IntegerLiteral [[ADDR_44:0x[a-z0-9]*]] 'int' 1 +// CXX-NEXT: | `-ImplicitCastExpr [[ADDR_45:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | `-DeclRefExpr [[ADDR_46:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// CXX-NEXT: `-ReturnStmt [[ADDR_47:0x[a-z0-9]*]] +// CXX-NEXT: `-BinaryOperator [[ADDR_48:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: |-BinaryOperator [[ADDR_49:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: | |-CallExpr [[ADDR_50:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | `-ImplicitCastExpr [[ADDR_51:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | `-ParenExpr [[ADDR_52:0x[a-z0-9]*]] 'int ({{.*}})' lvalue +// CXX-NEXT: | | `-BinaryOperator [[ADDR_53:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}',' +// CXX-NEXT: | | |-CallExpr [[ADDR_54:0x[a-z0-9]*]] 'void' +// CXX-NEXT: | | | `-ImplicitCastExpr [[ADDR_55:0x[a-z0-9]*]] 'void (*)({{.*}})' +// CXX-NEXT: | | | `-DeclRefExpr [[ADDR_56:0x[a-z0-9]*]] 'void ({{.*}})' {{.*}}Function [[ADDR_23]] 'foo' 'void ({{.*}})' +// CXX-NEXT: | | `-DeclRefExpr [[ADDR_57:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// CXX-NEXT: | `-CallExpr [[ADDR_58:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | `-ImplicitCastExpr [[ADDR_59:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' +// CXX-NEXT: | `-ParenExpr [[ADDR_60:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// CXX-NEXT: | `-ArraySubscriptExpr [[ADDR_61:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// CXX-NEXT: | |-ImplicitCastExpr [[ADDR_62:0x[a-z0-9]*]] 'fd *' +// CXX-NEXT: | | `-DeclRefExpr [[ADDR_63:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' +// CXX-NEXT: | `-IntegerLiteral [[ADDR_64:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: `-CallExpr [[ADDR_65:0x[a-z0-9]*]] 'int' +// CXX-NEXT: `-ImplicitCastExpr [[ADDR_66:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' +// CXX-NEXT: `-ParenExpr [[ADDR_67:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// CXX-NEXT: `-ArraySubscriptExpr [[ADDR_68:0x[a-z0-9]*]] 'fd':'int (*)({{.*}})' lvalue +// CXX-NEXT: |-IntegerLiteral [[ADDR_69:0x[a-z0-9]*]] 'int' 1 +// CXX-NEXT: `-ImplicitCastExpr [[ADDR_70:0x[a-z0-9]*]] 'fd *' +// CXX-NEXT: `-DeclRefExpr [[ADDR_71:0x[a-z0-9]*]] 'fd [2]' {{.*}}Var [[ADDR_32]] 'fns' 'fd [2]' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_addr_1.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_addr_1.c new file mode 100644 index 0000000000000..1cb39dac3c7f6 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_addr_1.c @@ -0,0 +1,151 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s --check-prefix=C +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s --check-prefix=CXX +// expected-no-diagnostics + +int also_before(void) { + return 0; +} + +#pragma omp begin declare variant match(implementation={vendor(llvm)}) +int also_after(void) { + return 1; +} +int also_before(void) { + return 2; +} +#pragma omp end declare variant + +int also_after(void) { + return 0; +} + +int test(int (*fd)(void)) { + return fd(); +} +int main() { + // Should return 0. + return test(also_after) + + test(also_before) + + test(&also_after) + + test(&also_before); +} + +// Make sure: +// - we see the specialization in the AST +// - we pick the right callees + +// CXX: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_5:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_6:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_7:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_7]] line:10:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 1 +// CXX-NEXT: |-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_12:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_13:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_14:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_14]] line:13:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_15:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_16:0x[a-z0-9]*]] +// CXX-NEXT: | `-IntegerLiteral [[ADDR_17:0x[a-z0-9]*]] 'int' 2 +// CXX-NEXT: |-FunctionDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_4]] line:18:5 used also_after 'int ({{.*}})' +// CXX-NEXT: | |-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// CXX-NEXT: | | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// CXX-NEXT: | | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 0 +// CXX-NEXT: | `-OMPDeclareVariantAttr [[ADDR_22:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(llvm)} +// CXX-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// CXX-NEXT: |-FunctionDecl [[ADDR_23:0x[a-z0-9]*]] line:22:5 used test 'int (int (*)({{.*}}))' +// CXX-NEXT: | |-ParmVarDecl [[ADDR_24:0x[a-z0-9]*]] col:16 used fd 'int (*)({{.*}})' +// CXX-NEXT: | `-CompoundStmt [[ADDR_25:0x[a-z0-9]*]] +// CXX-NEXT: | `-ReturnStmt [[ADDR_26:0x[a-z0-9]*]] +// CXX-NEXT: | `-CallExpr [[ADDR_27:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | `-ImplicitCastExpr [[ADDR_28:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | `-DeclRefExpr [[ADDR_29:0x[a-z0-9]*]] 'int (*)({{.*}})' {{.*}}ParmVar [[ADDR_24]] 'fd' 'int (*)({{.*}})' +// CXX-NEXT: `-FunctionDecl [[ADDR_30:0x[a-z0-9]*]] line:25:5 main 'int ({{.*}})' +// CXX-NEXT: `-CompoundStmt [[ADDR_31:0x[a-z0-9]*]] +// CXX-NEXT: `-ReturnStmt [[ADDR_32:0x[a-z0-9]*]] +// CXX-NEXT: `-BinaryOperator [[ADDR_33:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: |-BinaryOperator [[ADDR_34:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: | |-BinaryOperator [[ADDR_35:0x[a-z0-9]*]] 'int' '+' +// CXX-NEXT: | | |-CallExpr [[ADDR_36:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | | |-ImplicitCastExpr [[ADDR_37:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// CXX-NEXT: | | | | `-DeclRefExpr [[ADDR_38:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' {{.*}}Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// CXX-NEXT: | | | `-ImplicitCastExpr [[ADDR_39:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | | `-DeclRefExpr [[ADDR_40:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// CXX-NEXT: | | `-CallExpr [[ADDR_41:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | | |-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// CXX-NEXT: | | | `-DeclRefExpr [[ADDR_43:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' {{.*}}Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// CXX-NEXT: | | `-ImplicitCastExpr [[ADDR_44:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CXX-NEXT: | | `-DeclRefExpr [[ADDR_45:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// CXX-NEXT: | `-CallExpr [[ADDR_46:0x[a-z0-9]*]] 'int' +// CXX-NEXT: | |-ImplicitCastExpr [[ADDR_47:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// CXX-NEXT: | | `-DeclRefExpr [[ADDR_48:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' {{.*}}Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// CXX-NEXT: | `-UnaryOperator [[ADDR_49:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// CXX-NEXT: | `-DeclRefExpr [[ADDR_50:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// CXX-NEXT: `-CallExpr [[ADDR_51:0x[a-z0-9]*]] 'int' +// CXX-NEXT: |-ImplicitCastExpr [[ADDR_52:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// CXX-NEXT: | `-DeclRefExpr [[ADDR_53:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' {{.*}}Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// CXX-NEXT: `-UnaryOperator [[ADDR_54:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// CXX-NEXT: `-DeclRefExpr [[ADDR_55:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_11]] 'also_before' 'int ({{.*}})' + +// C: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] col:5 implicit used also_after 'int ({{.*}})' +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_5:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_6:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_7:0x[a-z0-9]*]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_7]] line:10:1 also_after[implementation={vendor(llvm)}] 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 1 +// C-NEXT: |-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 implicit used also_before 'int ({{.*}})' +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_12:0x[a-z0-9]*]] <> Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_13:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_14:0x[a-z0-9]*]] 'also_before[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_14]] line:13:1 also_before[implementation={vendor(llvm)}] 'int ({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_15:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_16:0x[a-z0-9]*]] +// C-NEXT: | `-IntegerLiteral [[ADDR_17:0x[a-z0-9]*]] 'int' 2 +// C-NEXT: |-FunctionDecl [[ADDR_18:0x[a-z0-9]*]] prev [[ADDR_4]] line:18:5 used also_after 'int ({{.*}})' +// C-NEXT: | |-CompoundStmt [[ADDR_19:0x[a-z0-9]*]] +// C-NEXT: | | `-ReturnStmt [[ADDR_20:0x[a-z0-9]*]] +// C-NEXT: | | `-IntegerLiteral [[ADDR_21:0x[a-z0-9]*]] 'int' 0 +// C-NEXT: | `-OMPDeclareVariantAttr [[ADDR_22:0x[a-z0-9]*]] <> Inherited Implicit implementation={vendor(llvm)} +// C-NEXT: | `-DeclRefExpr [[ADDR_6]] 'int ({{.*}})' Function [[ADDR_7]] 'also_after[implementation={vendor(llvm)}]' 'int ({{.*}})' +// C-NEXT: |-FunctionDecl [[ADDR_23:0x[a-z0-9]*]] line:22:5 used test 'int (int (*)({{.*}}))' +// C-NEXT: | |-ParmVarDecl [[ADDR_24:0x[a-z0-9]*]] col:16 used fd 'int (*)({{.*}})' +// C-NEXT: | `-CompoundStmt [[ADDR_25:0x[a-z0-9]*]] +// C-NEXT: | `-ReturnStmt [[ADDR_26:0x[a-z0-9]*]] +// C-NEXT: | `-CallExpr [[ADDR_27:0x[a-z0-9]*]] 'int' +// C-NEXT: | `-ImplicitCastExpr [[ADDR_28:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | `-DeclRefExpr [[ADDR_29:0x[a-z0-9]*]] 'int (*)({{.*}})' {{.*}}ParmVar [[ADDR_24]] 'fd' 'int (*)({{.*}})' +// C-NEXT: `-FunctionDecl [[ADDR_30:0x[a-z0-9]*]] line:25:5 main 'int ({{.*}})' +// C-NEXT: `-CompoundStmt [[ADDR_31:0x[a-z0-9]*]] +// C-NEXT: `-ReturnStmt [[ADDR_32:0x[a-z0-9]*]] +// C-NEXT: `-BinaryOperator [[ADDR_33:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: |-BinaryOperator [[ADDR_34:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: | |-BinaryOperator [[ADDR_35:0x[a-z0-9]*]] 'int' '+' +// C-NEXT: | | |-CallExpr [[ADDR_36:0x[a-z0-9]*]] 'int' +// C-NEXT: | | | |-ImplicitCastExpr [[ADDR_37:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// C-NEXT: | | | | `-DeclRefExpr [[ADDR_38:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// C-NEXT: | | | `-ImplicitCastExpr [[ADDR_39:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | | `-DeclRefExpr [[ADDR_40:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// C-NEXT: | | `-CallExpr [[ADDR_41:0x[a-z0-9]*]] 'int' +// C-NEXT: | | |-ImplicitCastExpr [[ADDR_42:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// C-NEXT: | | | `-DeclRefExpr [[ADDR_43:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// C-NEXT: | | `-ImplicitCastExpr [[ADDR_44:0x[a-z0-9]*]] 'int (*)({{.*}})' +// C-NEXT: | | `-DeclRefExpr [[ADDR_45:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_11]] 'also_before' 'int ({{.*}})' +// C-NEXT: | `-CallExpr [[ADDR_46:0x[a-z0-9]*]] 'int' +// C-NEXT: | |-ImplicitCastExpr [[ADDR_47:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// C-NEXT: | | `-DeclRefExpr [[ADDR_48:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// C-NEXT: | `-UnaryOperator [[ADDR_49:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// C-NEXT: | `-DeclRefExpr [[ADDR_50:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_18]] 'also_after' 'int ({{.*}})' +// C-NEXT: `-CallExpr [[ADDR_51:0x[a-z0-9]*]] 'int' +// C-NEXT: |-ImplicitCastExpr [[ADDR_52:0x[a-z0-9]*]] 'int (*)(int (*)({{.*}}))' +// C-NEXT: | `-DeclRefExpr [[ADDR_53:0x[a-z0-9]*]] 'int (int (*)({{.*}}))' Function [[ADDR_23]] 'test' 'int (int (*)({{.*}}))' +// C-NEXT: `-UnaryOperator [[ADDR_54:0x[a-z0-9]*]] 'int (*)({{.*}})' prefix '&' cannot overflow +// C-NEXT: `-DeclRefExpr [[ADDR_55:0x[a-z0-9]*]] 'int ({{.*}})' Function [[ADDR_11]] 'also_before' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-openmp-begin-declare-variant_decl_1.c b/clang/test/AST/ast-dump-openmp-begin-declare-variant_decl_1.c new file mode 100644 index 0000000000000..2cf28058703c6 --- /dev/null +++ b/clang/test/AST/ast-dump-openmp-begin-declare-variant_decl_1.c @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fopenmp -verify -ast-dump %s -x c++| FileCheck %s +// expected-no-diagnostics +// FIXME: We have to improve the warnings here as nothing is impacted by the declare variant. +int also_before(void) { + return 0; +} + +#pragma omp begin declare variant match(device={kind(cpu)}) +int also_before(void); +#pragma omp end declare variant +#pragma omp begin declare variant match(implementation={vendor(score(100):llvm)}) +int also_after(void); +#pragma omp end declare variant +#pragma omp begin declare variant match(implementation={vendor(score(0):llvm)}) +int also_before(void); +#pragma omp end declare variant + +int also_after(void) { + return 0; +} + +int test() { + // Should return 0. + return also_after() + also_before(); +} + +// Make sure: +// - we do see the ast nodes for the cpu kind +// - we do see the ast nodes for the llvm vendor +// - we pick the right callees + +// CHECK: |-FunctionDecl [[ADDR_0:0x[a-z0-9]*]] <{{.*}}, line:7:1> line:5:5 used also_before 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_1:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_2:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_3:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: |-FunctionDecl [[ADDR_4:0x[a-z0-9]*]] prev [[ADDR_0]] col:5 used also_before 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_5:0x[a-z0-9]*]] col:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_6:0x[a-z0-9]*]] prev [[ADDR_4]] col:5 used also_before 'int ({{.*}})' +// CHECK-NEXT: |-FunctionDecl [[ADDR_7:0x[a-z0-9]*]] prev [[ADDR_5]] line:19:5 used also_after 'int ({{.*}})' +// CHECK-NEXT: | `-CompoundStmt [[ADDR_8:0x[a-z0-9]*]] +// CHECK-NEXT: | `-ReturnStmt [[ADDR_9:0x[a-z0-9]*]] +// CHECK-NEXT: | `-IntegerLiteral [[ADDR_10:0x[a-z0-9]*]] 'int' 0 +// CHECK-NEXT: `-FunctionDecl [[ADDR_11:0x[a-z0-9]*]] line:23:5 test 'int ({{.*}})' +// CHECK-NEXT: `-CompoundStmt [[ADDR_12:0x[a-z0-9]*]] +// CHECK-NEXT: `-ReturnStmt [[ADDR_13:0x[a-z0-9]*]] +// CHECK-NEXT: `-BinaryOperator [[ADDR_14:0x[a-z0-9]*]] 'int' '+' +// CHECK-NEXT: |-CallExpr [[ADDR_15:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: | `-ImplicitCastExpr [[ADDR_16:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: | `-DeclRefExpr [[ADDR_17:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_7]] 'also_after' 'int ({{.*}})' +// CHECK-NEXT: `-CallExpr [[ADDR_18:0x[a-z0-9]*]] 'int' +// CHECK-NEXT: `-ImplicitCastExpr [[ADDR_19:0x[a-z0-9]*]] 'int (*)({{.*}})' +// CHECK-NEXT: `-DeclRefExpr [[ADDR_20:0x[a-z0-9]*]] 'int ({{.*}})' {{.*}}Function [[ADDR_6]] 'also_before' 'int ({{.*}})' diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp index beb409edc4a6a..9ccfc5a106f89 100644 --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -83,3 +83,18 @@ int binary = a + nullptr; // CHECK-NEXT: `-DeclRefExpr {{.*}} 'a' // DISABLED-NOT: -RecoveryExpr {{.*}} contains-errors int ternary = a ? nullptr : a; + +// CHECK: FunctionDecl +// CHECK-NEXT:|-ParmVarDecl {{.*}} x +// CHECK-NEXT:`-CompoundStmt +// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'foo' +// CHECK-NEXT: `-CallExpr {{.*}} contains-errors +// CHECK-NEXT: |-RecoveryExpr {{.*}} contains-errors +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'foo' +// CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' +struct Foo {} foo; +void test(int x) { + foo.abc; + foo->func(x); +} \ No newline at end of file diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c index 55f15f6d37c8f..6f719ec15d4f5 100644 --- a/clang/test/Analysis/analyzer-enabled-checkers.c +++ b/clang/test/Analysis/analyzer-enabled-checkers.c @@ -7,11 +7,11 @@ // CHECK: OVERVIEW: Clang Static Analyzer Enabled Checkers List // CHECK-EMPTY: // CHECK-NEXT: apiModeling.StdCLibraryFunctions +// CHECK-NEXT: core.CallAndMessage // CHECK-NEXT: apiModeling.StdCLibraryFunctionArgs // CHECK-NEXT: apiModeling.TrustNonnull // CHECK-NEXT: apiModeling.llvm.CastValue // CHECK-NEXT: apiModeling.llvm.ReturnValue -// CHECK-NEXT: core.CallAndMessage // CHECK-NEXT: core.DivideZero // CHECK-NEXT: core.DynamicTypePropagation // CHECK-NEXT: core.NonNullParamChecker diff --git a/clang/test/Analysis/container-modeling-no-aggressive-binary-operation-simplification-warn.cpp b/clang/test/Analysis/container-modeling-no-aggressive-binary-operation-simplification-warn.cpp new file mode 100644 index 0000000000000..1a55e878f9ef0 --- /dev/null +++ b/clang/test/Analysis/container-modeling-no-aggressive-binary-operation-simplification-warn.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_analyze_cc1 -std=c++11\ +// RUN: -analyzer-checker=core,cplusplus,alpha.cplusplus.ContainerModeling\ +// RUN: %s 2>&1 | FileCheck %s + +// XFAIL: * + +// CHECK: checker cannot be enabled with analyzer option 'aggressive-binary-operation-simplification' == false diff --git a/clang/test/Analysis/container-modeling.cpp b/clang/test/Analysis/container-modeling.cpp index 8162ba9039e80..bf4a12a0e0fe2 100644 --- a/clang/test/Analysis/container-modeling.cpp +++ b/clang/test/Analysis/container-modeling.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -analyzer-output=text -verify -// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -analyzer-output=text -verify // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true %s 2>&1 | FileCheck %s @@ -20,14 +20,16 @@ void begin(const std::vector &V) { V.begin(); clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); - clang_analyzer_express(clang_analyzer_container_begin(V)); //expected-warning{{$V.begin()}} + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + // expected-note@-1{{$V.begin()}} } void end(const std::vector &V) { V.end(); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); - clang_analyzer_express(clang_analyzer_container_end(V)); //expected-warning{{$V.end()}} + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end()}} + // expected-note@-1{{$V.end()}} } //////////////////////////////////////////////////////////////////////////////// @@ -48,8 +50,10 @@ void move_assignment(std::vector &V1, std::vector &V2) { long B2 = clang_analyzer_container_begin(V2); long E2 = clang_analyzer_container_end(V2); V1 = std::move(V2); - clang_analyzer_eval(clang_analyzer_container_begin(V1) == B2); //expected-warning{{TRUE}} - clang_analyzer_eval(clang_analyzer_container_end(V2) == E2); //expected-warning{{TRUE}} + clang_analyzer_eval(clang_analyzer_container_begin(V1) == B2); // expected-warning{{TRUE}} + // expected-note@-1{{TRUE}} + clang_analyzer_eval(clang_analyzer_container_end(V2) == E2); // expected-warning{{TRUE}} + // expected-note@-1{{TRUE}} } //////////////////////////////////////////////////////////////////////////////// @@ -60,9 +64,11 @@ void move_assignment(std::vector &V1, std::vector &V2) { /// push_back() /// -/// Design decision: extends containers to the ->RIGHT-> (i.e. the +/// Design decision: extends containers to the ->BACK-> (i.e. the /// past-the-end position of the container is incremented). +void clang_analyzer_dump(void*); + void push_back(std::vector &V, int n) { V.cbegin(); V.cend(); @@ -70,15 +76,17 @@ void push_back(std::vector &V, int n) { clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); - V.push_back(n); + V.push_back(n); // expected-note 2{{Container 'V' extended to the back by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + // expected-note@-1{{$V.begin()}} clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} + // expected-note@-1{{$V.end() + 1}} } /// emplace_back() /// -/// Design decision: extends containers to the ->RIGHT-> (i.e. the +/// Design decision: extends containers to the ->BACK-> (i.e. the /// past-the-end position of the container is incremented). void emplace_back(std::vector &V, int n) { @@ -88,15 +96,17 @@ void emplace_back(std::vector &V, int n) { clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); - V.emplace_back(n); + V.emplace_back(n); // expected-note 2{{Container 'V' extended to the back by 1 position}} clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + // expected-note@-1{{$V.begin()}} clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} + // expected-note@-1{{$V.end() + 1}} } /// pop_back() /// -/// Design decision: shrinks containers to the <-LEFT<- (i.e. the +/// Design decision: shrinks containers to the <-FRONT<- (i.e. the /// past-the-end position of the container is decremented). void pop_back(std::vector &V, int n) { @@ -106,66 +116,132 @@ void pop_back(std::vector &V, int n) { clang_analyzer_denote(clang_analyzer_container_begin(V), "$V.begin()"); clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); - V.pop_back(); + V.pop_back(); // expected-note 2{{Container 'V' shrank from the back by 1 position}} + clang_analyzer_express(clang_analyzer_container_begin(V)); // expected-warning{{$V.begin()}} + // expected-note@-1{{$V.begin()}} clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() - 1}} + // expected-note@-1{{$V.end() - 1}} } /// push_front() /// -/// Design decision: extends containers to the <-LEFT<- (i.e. the first +/// Design decision: extends containers to the <-FRONT<- (i.e. the first /// position of the container is decremented). -void push_front(std::deque &D, int n) { - D.cbegin(); - D.cend(); +void push_front(std::list &L, int n) { + L.cbegin(); + L.cend(); - clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); - clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); - D.push_front(n); + L.push_front(n); // expected-note 2{{Container 'L' extended to the front by 1 position}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin() - 1 (to correctly track the container's size) - clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} + // expected-note@-1{{$L.begin() - 1}} + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + // expected-note@-1{{$L.end()}} } /// emplace_front() /// -/// Design decision: extends containers to the <-LEFT<- (i.e. the first +/// Design decision: extends containers to the <-FRONT<- (i.e. the first /// position of the container is decremented). -void deque_emplace_front(std::deque &D, int n) { - D.cbegin(); - D.cend(); +void emplace_front(std::list &L, int n) { + L.cbegin(); + L.cend(); - clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); - clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); - D.emplace_front(n); + L.emplace_front(n); // expected-note 2{{Container 'L' extended to the front by 1 position}} - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin()}} FIXME: Should be $D.begin - 1 (to correctly track the container's size) - clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() - 1}} + // expected-note@-1{{$L.begin() - 1}} + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + // expected-note@-1{{$L.end()}} } /// pop_front() /// -/// Design decision: shrinks containers to the ->RIGHT-> (i.e. the first +/// Design decision: shrinks containers to the ->BACK-> (i.e. the first /// position of the container is incremented). -void deque_pop_front(std::deque &D, int n) { - D.cbegin(); - D.cend(); +void pop_front(std::list &L, int n) { + L.cbegin(); + L.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(L), "$L.begin()"); + clang_analyzer_denote(clang_analyzer_container_end(L), "$L.end()"); + + L.pop_front(); // expected-note 2{{Container 'L' shrank from the front by 1 position}} + + clang_analyzer_express(clang_analyzer_container_begin(L)); // expected-warning{{$L.begin() + 1}} + // expected-note@-1{{$L.begin() + 1}} + clang_analyzer_express(clang_analyzer_container_end(L)); // expected-warning{{$L.end()}} + // expected-note@-1{{$L.end()}} +} + +//////////////////////////////////////////////////////////////////////////////// +/// +/// O T H E R T E S T S +/// +//////////////////////////////////////////////////////////////////////////////// + +/// Track local variable + +void push_back() { + std::vector V; + V.end(); + + clang_analyzer_denote(clang_analyzer_container_end(V), "$V.end()"); + + V.push_back(1); // expected-note{{Container 'V' extended to the back by 1 position}} + + clang_analyzer_express(clang_analyzer_container_end(V)); // expected-warning{{$V.end() + 1}} + // expected-note@-1{{$V.end() + 1}} +} + +/// Track the right container only + +void push_back1(std::vector &V1, std::vector &V2, int n) { + V1.cbegin(); + V1.cend(); + V2.cbegin(); + V2.cend(); - clang_analyzer_denote(clang_analyzer_container_begin(D), "$D.begin()"); - clang_analyzer_denote(clang_analyzer_container_end(D), "$D.end()"); + clang_analyzer_denote(clang_analyzer_container_begin(V1), "$V1.begin()"); - D.pop_front(); + V2.push_back(n); // no-note - clang_analyzer_express(clang_analyzer_container_begin(D)); // expected-warning{{$D.begin() + 1}} - clang_analyzer_express(clang_analyzer_container_end(D)); // expected-warning{{$D.end()}} + clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V1.begin()}} + // expected-note@-1{{$V1.begin()}} } +void push_back2(std::vector &V1, std::vector &V2, int n) { + V1.cbegin(); + V1.cend(); + V2.cbegin(); + V2.cend(); + + clang_analyzer_denote(clang_analyzer_container_begin(V1), "$V1.begin()"); + clang_analyzer_denote(clang_analyzer_container_begin(V2), "$V2.begin()"); + + V1.push_back(n); // expected-note{{Container 'V1' extended to the back by 1 position}} + // Only once! + + clang_analyzer_express(clang_analyzer_container_begin(V1)); // expected-warning{{$V1.begin()}} + // expected-note@-1{{$V1.begin()}} + + clang_analyzer_express(clang_analyzer_container_begin(V2)); // expected-warning{{$V2.begin()}} + // expected-note@-1{{$V2.begin()}} +} + +/// Print Container Data as Part of the Program State + void clang_analyzer_printState(); void print_state(std::vector &V) { diff --git a/clang/test/Analysis/iterator-modeling-no-aggressive-binary-operation-simplification-no-crash.cpp b/clang/test/Analysis/iterator-modeling-no-aggressive-binary-operation-simplification-no-crash.cpp new file mode 100644 index 0000000000000..4b7c52db54627 --- /dev/null +++ b/clang/test/Analysis/iterator-modeling-no-aggressive-binary-operation-simplification-no-crash.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_analyze_cc1 -std=c++11\ +// RUN: -analyzer-checker=core,cplusplus,debug.DebugIteratorModeling,debug.ExprInspection\ +// RUN: %s 2>&1 | FileCheck %s + +// XFAIL: * + +// CHECK: checker cannot be enabled with analyzer option 'aggressive-binary-operation-simplification' == false + +#include "Inputs/system-header-simulator-cxx.h" + +void clang_analyzer_eval(bool); + +void comparison(std::vector &V) { + clang_analyzer_eval(V.begin() == V.end()); // no-crash +} diff --git a/clang/test/Analysis/iterator-modelling.cpp b/clang/test/Analysis/iterator-modeling.cpp similarity index 100% rename from clang/test/Analysis/iterator-modelling.cpp rename to clang/test/Analysis/iterator-modeling.cpp diff --git a/clang/test/Analysis/iterator-range.cpp b/clang/test/Analysis/iterator-range.cpp index babcfdec99d66..bdfb04ba3a8ca 100644 --- a/clang/test/Analysis/iterator-range.cpp +++ b/clang/test/Analysis/iterator-range.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false %s -verify -// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -analyzer-output=text %s -verify +// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -DINLINE=1 -analyzer-output=text %s -verify #include "Inputs/system-header-simulator-cxx.h" @@ -32,6 +32,7 @@ void deref_ahead_of_end(const std::vector &V) { void deref_end(const std::vector &V) { auto i = V.end(); *i; // expected-warning{{Past-the-end iterator dereferenced}} + // expected-note@-1{{Past-the-end iterator dereferenced}} } // Prefix increment - operator++() @@ -59,6 +60,7 @@ void incr_ahead_of_end(const std::vector &V) { void incr_end(const std::vector &V) { auto i = V.end(); ++i; // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // Postfix increment - operator++(int) @@ -86,6 +88,7 @@ void ahead_of_end_incr(const std::vector &V) { void end_incr(const std::vector &V) { auto i = V.end(); i++; // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // Prefix decrement - operator--() @@ -93,6 +96,7 @@ void end_incr(const std::vector &V) { void decr_begin(const std::vector &V) { auto i = V.begin(); --i; // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void decr_behind_begin(const std::vector &V) { @@ -120,6 +124,7 @@ void decr_end(const std::vector &V) { void begin_decr(const std::vector &V) { auto i = V.begin(); i--; // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void behind_begin_decr(const std::vector &V) { @@ -168,11 +173,13 @@ void incr_by_2_ahead_by_2_of_end(const std::vector &V) { void incr_by_2_ahead_of_end(const std::vector &V) { auto i = --V.end(); i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } void incr_by_2_end(const std::vector &V) { auto i = V.end(); i += 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // Addition - operator+(int) @@ -201,11 +208,13 @@ void incr_by_2_copy_ahead_by_2_of_end(const std::vector &V) { void incr_by_2_copy_ahead_of_end(const std::vector &V) { auto i = --V.end(); auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } void incr_by_2_copy_end(const std::vector &V) { auto i = V.end(); auto j = i + 2; // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // Subtraction assignment - operator-=(int) @@ -213,11 +222,13 @@ void incr_by_2_copy_end(const std::vector &V) { void decr_by_2_begin(const std::vector &V) { auto i = V.begin(); i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void decr_by_2_behind_begin(const std::vector &V) { auto i = ++V.begin(); i -= 2; // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void decr_by_2_behind_begin_by_2(const std::vector &V) { @@ -246,11 +257,13 @@ void decr_by_2_end(const std::vector &V) { void decr_by_2_copy_begin(const std::vector &V) { auto i = V.begin(); auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void decr_by_2_copy_behind_begin(const std::vector &V) { auto i = ++V.begin(); auto j = i - 2; // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void decr_by_2_copy_behind_begin_by_2(const std::vector &V) { @@ -303,6 +316,7 @@ void subscript_zero_ahead_of_end(const std::vector &V) { void subscript_zero_end(const std::vector &V) { auto i = V.end(); auto j = i[0]; // expected-warning{{Past-the-end iterator dereferenced}} + // expected-note@-1{{Past-the-end iterator dereferenced}} } // By negative number @@ -329,7 +343,8 @@ void subscript_negative_ahead_of_end(const std::vector &V) { void subscript_negative_end(const std::vector &V) { auto i = V.end(); - auto j = i[-1]; // // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect no warning + auto j = i[-1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect no warning + // expected-note@-1{{Past-the-end iterator dereferenced}} } // By positive number @@ -357,6 +372,7 @@ void subscript_positive_ahead_of_end(const std::vector &V) { void subscript_positive_end(const std::vector &V) { auto i = V.end(); auto j = i[1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect warning Iterator incremented behind the past-the-end iterator + // expected-note@-1{{Past-the-end iterator dereferenced}} FIXME: expect note@-1 Iterator incremented behind the past-the-end iterator } // @@ -388,6 +404,7 @@ void advance_plus_1_ahead_of_end(const std::vector &V) { void advance_plus_1_end(const std::vector &V) { auto i = V.end(); std::advance(i, 1); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // std::advance() by -1 @@ -395,6 +412,7 @@ void advance_plus_1_end(const std::vector &V) { void advance_minus_1_begin(const std::vector &V) { auto i = V.begin(); std::advance(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void advance_minus_1_behind_begin(const std::vector &V) { @@ -437,11 +455,13 @@ void advance_plus_2_unknown(const std::vector &V) { void advance_plus_2_ahead_of_end(const std::vector &V) { auto i = --V.end(); std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } void advance_plus_2_end(const std::vector &V) { auto i = V.end(); std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // std::advance() by -2 @@ -449,11 +469,13 @@ void advance_plus_2_end(const std::vector &V) { void advance_minus_2_begin(const std::vector &V) { auto i = V.begin(); std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void advance_minus_2_behind_begin(const std::vector &V) { auto i = ++V.begin(); std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void advance_minus_2_unknown(const std::vector &V) { @@ -527,6 +549,7 @@ void next_plus_1_ahead_of_end(const std::vector &V) { void next_plus_1_end(const std::vector &V) { auto i = V.end(); auto j = std::next(i); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // std::next() by -1 @@ -534,6 +557,7 @@ void next_plus_1_end(const std::vector &V) { void next_minus_1_begin(const std::vector &V) { auto i = V.begin(); auto j = std::next(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void next_minus_1_behind_begin(const std::vector &V) { @@ -576,11 +600,13 @@ void next_plus_2_unknown(const std::vector &V) { void next_plus_2_ahead_of_end(const std::vector &V) { auto i = --V.end(); auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } void next_plus_2_end(const std::vector &V) { auto i = V.end(); auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // std::next() by -2 @@ -588,11 +614,13 @@ void next_plus_2_end(const std::vector &V) { void next_minus_2_begin(const std::vector &V) { auto i = V.begin(); auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void next_minus_2_behind_begin(const std::vector &V) { auto i = ++V.begin(); auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void next_minus_2_unknown(const std::vector &V) { @@ -646,6 +674,7 @@ void next_0_end(const std::vector &V) { void prev_plus_1_begin(const std::vector &V) { auto i = V.begin(); auto j = std::prev(i); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void prev_plus_1_behind_begin(const std::vector &V) { @@ -693,6 +722,7 @@ void prev_minus_1_ahead_of_end(const std::vector &V) { void prev_minus_1_end(const std::vector &V) { auto i = V.end(); auto j = std::prev(i, -1); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // std::prev() by +2 @@ -700,11 +730,13 @@ void prev_minus_1_end(const std::vector &V) { void prev_plus_2_begin(const std::vector &V) { auto i = V.begin(); auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void prev_plus_2_behind_begin(const std::vector &V) { auto i = ++V.begin(); auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}} + // expected-note@-1{{Iterator decremented ahead of its valid range}} } void prev_plus_2_unknown(const std::vector &V) { @@ -742,11 +774,13 @@ void prev_minus_2_unknown(const std::vector &V) { void prev_minus_2_ahead_of_end(const std::vector &V) { auto i = --V.end(); auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } void prev_minus_2_end(const std::vector &V) { auto i = V.end(); auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} + // expected-note@-1{{Iterator incremented behind the past-the-end iterator}} } // std::prev() by 0 @@ -793,5 +827,17 @@ void arrow_deref_begin(const std::vector &V) { void arrow_deref_end(const std::vector &V) { auto i = V.end(); - int n = i->n; // expected-warning{{Past-the-end iterator dereferenced}} + int n = i->n; // expected-warning{{Past-the-end iterator dereferenced}} + // expected-note@-1{{Past-the-end iterator dereferenced}} +} + +// Container modification - test path notes + +void deref_end_after_pop_back(std::vector &V) { + const auto i = --V.end(); + + V.pop_back(); // expected-note{{Container 'V' shrank from the back by 1 position}} + + *i; // expected-warning{{Past-the-end iterator dereferenced}} + // expected-note@-1{{Past-the-end iterator dereferenced}} } diff --git a/clang/test/Analysis/kmalloc-linux.c b/clang/test/Analysis/kmalloc-linux.c index ccb6188a51b3d..4cca5712b0967 100644 --- a/clang/test/Analysis/kmalloc-linux.c +++ b/clang/test/Analysis/kmalloc-linux.c @@ -1,4 +1,7 @@ -// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux %s +// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux %s -verify \ +// RUN: -Wno-incompatible-library-redeclaration \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=unix.Malloc #define __GFP_ZERO 0x8000 #define NULL ((void *)0) @@ -6,6 +9,7 @@ typedef __typeof(sizeof(int)) size_t; void *kmalloc(size_t, int); +void kfree(void *); struct test { }; @@ -61,6 +65,8 @@ typedef unsigned long long uint64_t; struct malloc_type; +// 3 parameter malloc: +// https://www.freebsd.org/cgi/man.cgi?query=malloc&sektion=9 void *malloc(unsigned long size, struct malloc_type *mtp, int flags); void test_3arg_malloc(struct malloc_type *mtp) { @@ -97,7 +103,7 @@ void test_3arg_malloc_indeterminate(struct malloc_type *mtp, int flags) { struct test **list, *t; int i; - list = alloc(sizeof(*list) * 10, mtp, flags); + list = malloc(sizeof(*list) * 10, mtp, flags); if (list == NULL) return; @@ -107,3 +113,25 @@ void test_3arg_malloc_indeterminate(struct malloc_type *mtp, int flags) { } kfree(list); } + +void test_3arg_malloc_leak(struct malloc_type *mtp, int flags) { + struct test **list; + + list = malloc(sizeof(*list) * 10, mtp, flags); + if (list == NULL) + return; +} // expected-warning{{Potential leak of memory pointed to by 'list'}} + +// kmalloc can return a constant value defined in ZERO_SIZE_PTR +// if a block of size 0 is requested +#define ZERO_SIZE_PTR ((void *)16) + +void test_kfree_ZERO_SIZE_PTR() { + void *ptr = ZERO_SIZE_PTR; + kfree(ptr); // no warning about freeing this value +} + +void test_kfree_other_constant_value() { + void *ptr = (void *)1; + kfree(ptr); // expected-warning{{Argument to kfree() is a constant address (1)}} +} diff --git a/clang/test/Analysis/loop-widening-notes.cpp b/clang/test/Analysis/loop-widening-notes.cpp index 2c26a1490e5c2..0ba71d030d058 100644 --- a/clang/test/Analysis/loop-widening-notes.cpp +++ b/clang/test/Analysis/loop-widening-notes.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha -analyzer-max-loop 2 -analyzer-config widen-loops=true -analyzer-output=text -verify -analyzer-config eagerly-assume=false %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -analyzer-max-loop 2 -analyzer-config widen-loops=true -analyzer-output=text -verify -analyzer-config eagerly-assume=false %s int *p_a; int bar(); diff --git a/clang/test/Analysis/malloc.cpp b/clang/test/Analysis/malloc.cpp index 6e5a0e4d59715..cc7fefe23d75a 100644 --- a/clang/test/Analysis/malloc.cpp +++ b/clang/test/Analysis/malloc.cpp @@ -164,3 +164,11 @@ void test(A a) { (void)a.getName(); } } // namespace argument_leak + +#define ZERO_SIZE_PTR ((void *)16) + +void test_delete_ZERO_SIZE_PTR() { + int *Ptr = (int *)ZERO_SIZE_PTR; + // ZERO_SIZE_PTR is specially handled but only for malloc family + delete Ptr; // expected-warning{{Argument to 'delete' is a constant address (16)}} +} diff --git a/clang/test/Analysis/osobject-retain-release.cpp b/clang/test/Analysis/osobject-retain-release.cpp index 41606a30c39f4..d88349dcd807e 100644 --- a/clang/test/Analysis/osobject-retain-release.cpp +++ b/clang/test/Analysis/osobject-retain-release.cpp @@ -53,6 +53,9 @@ struct MyArray : public OSArray { OSObject *generateObject(OSObject *input) override; }; +// These are never refcounted. +struct OSSymbol : OSObject {}; + struct OtherStruct { static void doNothingToArray(OSArray *array); OtherStruct(OSArray *arr); @@ -754,3 +757,10 @@ void test() { b(0); } } // namespace inherited_constructor_crash + +namespace ossymbol_suppression { +OSSymbol *createSymbol(); +void test() { + OSSymbol *sym = createSymbol(); // no-warning +} +} // namespace ossymbol_suppression diff --git a/clang/test/Analysis/std-c-library-functions-arg-constraints.c b/clang/test/Analysis/std-c-library-functions-arg-constraints.c index a20b90ad1ccb1..9753f9eb00cca 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-constraints.c +++ b/clang/test/Analysis/std-c-library-functions-arg-constraints.c @@ -3,6 +3,7 @@ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \ // RUN: -analyzer-checker=apiModeling.StdCLibraryFunctionArgs \ +// RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \ // RUN: -analyzer-checker=debug.ExprInspection \ // RUN: -triple x86_64-unknown-linux-gnu \ // RUN: -verify=report @@ -12,6 +13,7 @@ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=apiModeling.StdCLibraryFunctions \ // RUN: -analyzer-checker=apiModeling.StdCLibraryFunctionArgs \ +// RUN: -analyzer-checker=debug.StdCLibraryFunctionsTester \ // RUN: -analyzer-checker=debug.ExprInspection \ // RUN: -triple x86_64-unknown-linux-gnu \ // RUN: -analyzer-output=text \ @@ -85,3 +87,30 @@ void test_notnull_symbolic2(FILE *fp, int *buf) { // bugpath-warning{{Function argument constraint is not satisfied}} \ // bugpath-note{{Function argument constraint is not satisfied}} } + +int __two_constrained_args(int, int); +void test_constraints_on_multiple_args(int x, int y) { + // State split should not happen here. I.e. x == 1 should not be evaluated + // FALSE. + __two_constrained_args(x, y); + clang_analyzer_eval(x == 1); // \ + // report-warning{{TRUE}} \ + // bugpath-warning{{TRUE}} \ + // bugpath-note{{TRUE}} + clang_analyzer_eval(y == 1); // \ + // report-warning{{TRUE}} \ + // bugpath-warning{{TRUE}} \ + // bugpath-note{{TRUE}} +} + +int __arg_constrained_twice(int); +void test_multiple_constraints_on_same_arg(int x) { + __arg_constrained_twice(x); + // Check that both constraints are applied and only one branch is there. + clang_analyzer_eval(x < 1 || x > 2); // \ + // report-warning{{TRUE}} \ + // bugpath-warning{{TRUE}} \ + // bugpath-note{{TRUE}} \ + // bugpath-note{{Assuming 'x' is < 1}} \ + // bugpath-note{{Left side of '||' is true}} +} diff --git a/clang/test/Analysis/std-c-library-functions.c b/clang/test/Analysis/std-c-library-functions.c index 3f700a7c39a45..a275ea6720ade 100644 --- a/clang/test/Analysis/std-c-library-functions.c +++ b/clang/test/Analysis/std-c-library-functions.c @@ -89,6 +89,14 @@ void test_fread_fwrite(FILE *fp, int *buf) { clang_analyzer_eval(z <= y); // expected-warning{{TRUE}} } +void test_fread_uninitialized(void) { + void *ptr; + size_t sz; + size_t nmem; + FILE *fp; + (void)fread(ptr, sz, nmem, fp); // expected-warning {{1st function call argument is an uninitialized value}} +} + ssize_t getline(char **, size_t *, FILE *); void test_getline(FILE *fp) { char *line = 0; diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt index 5a09a8fb067a2..21584b6e58aa5 100644 --- a/clang/test/CMakeLists.txt +++ b/clang/test/CMakeLists.txt @@ -35,6 +35,16 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py MAIN_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/lit.cfg.py + PATHS + "LLVM_SOURCE_DIR" + "LLVM_BINARY_DIR" + "LLVM_TOOLS_DIR" + "LLVM_LIBS_DIR" + "SHLIBDIR" + "LLVM_LIT_TOOLS_DIR" + "CLANG_BINARY_DIR" + "CLANG_SOURCE_DIR" + "CLANG_TOOLS_DIR" ) configure_lit_site_cfg( @@ -42,6 +52,13 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg.py MAIN_CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.cfg.py + PATHS + "LLVM_SOURCE_DIR" + "LLVM_BINARY_DIR" + "LLVM_TOOLS_DIR" + "LLVM_LIBS_DIR" + "CLANG_BINARY_DIR" + "SHLIBDIR" ) option(CLANG_TEST_USE_VG "Run Clang tests under Valgrind" OFF) @@ -81,6 +98,7 @@ endif () if (CLANG_BUILD_EXAMPLES) list(APPEND CLANG_TEST_DEPS + Attribute AnnotateFunctions clang-interpreter PrintFunctionNames diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp index f812ea1bd8bef..1afea99e8895c 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1-cxx11.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fdiagnostics-show-option -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s template struct set{}; diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp index bb6bb73ec7029..e3599db18350b 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -verify %s -// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -verify -std=c++98 %s -// RUN: %clang_cc1 -fsyntax-only -fdiagnostics-show-option -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s // C++98 [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is diff --git a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp index ef3b127ef82aa..8ac4e9733ebb3 100644 --- a/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp +++ b/clang/test/CXX/basic/basic.lookup/basic.lookup.unqual/p3.cpp @@ -60,7 +60,7 @@ namespace AnnexD_example { A a; f < a; #if __cplusplus > 201703L - // expected-error@-2 {{expected '>'}} + // expected-error@-2 {{expected '>'}} expected-note@-2 {{to match this '<'}} #endif (f) < a; } diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp index 7a5caef36e737..e3190245d240f 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-cxx03-extra-copy.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++03 -fdiagnostics-show-option -Wbind-to-temporary-copy -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++03 -Wbind-to-temporary-copy -verify %s // C++03 requires that we check for a copy constructor when binding a // reference to a temporary, since we are allowed to make a copy, Even diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp index a5edc32fa48c9..a1501fa563b10 100644 --- a/clang/test/CXX/drs/dr3xx.cpp +++ b/clang/test/CXX/drs/dr3xx.cpp @@ -20,7 +20,7 @@ namespace dr301 { // dr301: yes (void(*)(S, S))operator+; bool b = (void(*)(S, S))operator- < (void(*)(S, S))operator-; - bool c = (void(*)(S, S))operator+ < + bool c = (void(*)(S, S))operator+ < // expected-note {{to match this '<'}} (void(*)(S, S))operator-; // expected-error {{expected '>'}} } @@ -123,7 +123,7 @@ namespace dr305 { // dr305: no template using T2 = T; }; void k(Z *z) { - z->~T1(); // expected-error {{no member named 'T1' in 'dr305::Z'}} expected-error +{{}} + z->~T1(); // expected-error {{no member named 'T1' in 'dr305::Z'}} z->~T2(); // expected-error {{no member named '~int'}} z->~T2(); } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp index 71c87ffff8bce..b8903b884e0a3 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp @@ -63,7 +63,7 @@ template struct invalid { typename T::type x; }; // expected-error@-1 {{typename specifier refers to non-type member 'type' in 'D'}} using r1i5 = r1>; // expected-error@-1 {{constraints not satisfied for class template 'r1' [with T = invalid]}} -// expected-note@-2 {{while checking constraint satisfaction for template 'r1 >' required here}} +// expected-note@-2 {{while checking constraint satisfaction for template 'r1>' required here}} // mismatching template arguments @@ -191,4 +191,4 @@ namespace std_example { using c2 = C1_check; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}} using c3 = C2_check; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}} using c4 = C3_check; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}} -} \ No newline at end of file +} diff --git a/clang/test/CXX/temp/p3.cpp b/clang/test/CXX/temp/p3.cpp index e9fd8a3090e86..90f6397857aec 100644 --- a/clang/test/CXX/temp/p3.cpp +++ b/clang/test/CXX/temp/p3.cpp @@ -7,9 +7,7 @@ template struct S { template int S::a, S::b; // expected-error {{can only declare a single entity}} template struct A { static A a; } A::a; // expected-error {{expected ';' after struct}} \ - expected-error {{use of undeclared identifier 'T'}} \ - expected-error {{no member named 'a'}} \ - expected-warning {{extra qualification}} + expected-error {{use of undeclared identifier 'T'}} template struct B { } f(); // expected-error {{expected ';' after struct}} \ expected-error {{requires a type specifier}} diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp index 1c13bffa212f7..0c555b53f95e6 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp @@ -13,9 +13,9 @@ template struct E; eval> eA; eval> eB; -eval> eC; // expected-error{{implicit instantiation of undefined template 'eval >'}} -eval> eD; // expected-error{{implicit instantiation of undefined template 'eval >'}} -eval> eE; // expected-error{{implicit instantiation of undefined template 'eval >}} +eval> eC; // expected-error{{implicit instantiation of undefined template 'eval>'}} +eval> eD; // expected-error{{implicit instantiation of undefined template 'eval>'}} +eval> eE; // expected-error{{implicit instantiation of undefined template 'eval>}} template