| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| //===--- BracesAroundStatement.cpp - clang-tidy -------- ------------------===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| /// | ||
| /// \file | ||
| /// This file provides utilities to put braces around a statement. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "BracesAroundStatement.h" | ||
| #include "../utils/LexerUtils.h" | ||
| #include "LexerUtils.h" | ||
| #include "clang/AST/ASTContext.h" | ||
| #include "clang/Basic/CharInfo.h" | ||
| #include "clang/Basic/LangOptions.h" | ||
| #include "clang/Lex/Lexer.h" | ||
|
|
||
| namespace clang::tidy::utils { | ||
|
|
||
| BraceInsertionHints::operator bool() const { return DiagnosticPos.isValid(); } | ||
|
|
||
| bool BraceInsertionHints::offersFixIts() const { | ||
| return OpeningBracePos.isValid() && ClosingBracePos.isValid(); | ||
| } | ||
|
|
||
| unsigned BraceInsertionHints::resultingCompoundLineExtent( | ||
| const SourceManager &SourceMgr) const { | ||
| return SourceMgr.getSpellingLineNumber(ClosingBracePos) - | ||
| SourceMgr.getSpellingLineNumber(OpeningBracePos); | ||
| } | ||
|
|
||
| FixItHint BraceInsertionHints::openingBraceFixIt() const { | ||
| return OpeningBracePos.isValid() | ||
| ? FixItHint::CreateInsertion(OpeningBracePos, " {") | ||
| : FixItHint(); | ||
| } | ||
|
|
||
| FixItHint BraceInsertionHints::closingBraceFixIt() const { | ||
| return ClosingBracePos.isValid() | ||
| ? FixItHint::CreateInsertion(ClosingBracePos, ClosingBrace) | ||
| : FixItHint(); | ||
| } | ||
|
|
||
| static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, | ||
| const LangOptions &LangOpts) { | ||
| Token Tok; | ||
| SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); | ||
| const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts); | ||
| assert(!Invalid && "Expected a valid token."); | ||
|
|
||
| if (Invalid) | ||
| return tok::NUM_TOKENS; | ||
|
|
||
| return Tok.getKind(); | ||
| } | ||
|
|
||
| static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM, | ||
| const LangOptions &LangOpts) { | ||
| SourceLocation Loc = lexer::getUnifiedEndLoc(S, SM, LangOpts); | ||
| if (!Loc.isValid()) | ||
| return Loc; | ||
|
|
||
| // Start searching right after S. | ||
| Loc = Loc.getLocWithOffset(1); | ||
|
|
||
| for (;;) { | ||
| assert(Loc.isValid()); | ||
| while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) { | ||
| Loc = Loc.getLocWithOffset(1); | ||
| } | ||
|
|
||
| if (isVerticalWhitespace(*SM.getCharacterData(Loc))) { | ||
| // EOL, insert brace before. | ||
| break; | ||
| } | ||
| tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts); | ||
| if (TokKind != tok::comment) { | ||
| // Non-comment token, insert brace before. | ||
| break; | ||
| } | ||
|
|
||
| SourceLocation TokEndLoc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); | ||
| SourceRange TokRange(Loc, TokEndLoc); | ||
| StringRef Comment = Lexer::getSourceText( | ||
| CharSourceRange::getTokenRange(TokRange), SM, LangOpts); | ||
| if (Comment.starts_with("/*") && Comment.contains('\n')) { | ||
| // Multi-line block comment, insert brace before. | ||
| break; | ||
| } | ||
| // else: Trailing comment, insert brace after the newline. | ||
|
|
||
| // Fast-forward current token. | ||
| Loc = TokEndLoc; | ||
| } | ||
| return Loc; | ||
| } | ||
|
|
||
| BraceInsertionHints getBraceInsertionsHints(const Stmt *const S, | ||
| const LangOptions &LangOpts, | ||
| const SourceManager &SM, | ||
| SourceLocation StartLoc, | ||
| SourceLocation EndLocHint) { | ||
| // 1) If there's a corresponding "else" or "while", the check inserts "} " | ||
| // right before that token. | ||
| // 2) If there's a multi-line block comment starting on the same line after | ||
| // the location we're inserting the closing brace at, or there's a non-comment | ||
| // token, the check inserts "\n}" right before that token. | ||
| // 3) Otherwise the check finds the end of line (possibly after some block or | ||
| // line comments) and inserts "\n}" right before that EOL. | ||
| if (!S || isa<CompoundStmt>(S)) { | ||
| // Already inside braces. | ||
| return {}; | ||
| } | ||
|
|
||
| // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt. | ||
| // This NullStmt can be detected according to beginning token. | ||
| const SourceLocation StmtBeginLoc = S->getBeginLoc(); | ||
| if (isa<NullStmt>(S) && StmtBeginLoc.isValid() && | ||
| getTokenKind(StmtBeginLoc, SM, LangOpts) == tok::l_brace) | ||
| return {}; | ||
|
|
||
| if (StartLoc.isInvalid()) | ||
| return {}; | ||
|
|
||
| // Convert StartLoc to file location, if it's on the same macro expansion | ||
| // level as the start of the statement. We also need file locations for | ||
| // Lexer::getLocForEndOfToken working properly. | ||
| StartLoc = Lexer::makeFileCharRange( | ||
| CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM, | ||
| LangOpts) | ||
| .getBegin(); | ||
| if (StartLoc.isInvalid()) | ||
| return {}; | ||
| StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOpts); | ||
|
|
||
| // StartLoc points at the location of the opening brace to be inserted. | ||
| SourceLocation EndLoc; | ||
| std::string ClosingInsertion; | ||
| if (EndLocHint.isValid()) { | ||
| EndLoc = EndLocHint; | ||
| ClosingInsertion = "} "; | ||
| } else { | ||
| EndLoc = findEndLocation(*S, SM, LangOpts); | ||
| ClosingInsertion = "\n}"; | ||
| } | ||
|
|
||
| assert(StartLoc.isValid()); | ||
|
|
||
| // Change only if StartLoc and EndLoc are on the same macro expansion level. | ||
| // This will also catch invalid EndLoc. | ||
| // Example: LLVM_DEBUG( for(...) do_something() ); | ||
| // In this case fix-it cannot be provided as the semicolon which is not | ||
| // visible here is part of the macro. Adding braces here would require adding | ||
| // another semicolon. | ||
| if (Lexer::makeFileCharRange( | ||
| CharSourceRange::getTokenRange(SourceRange( | ||
| SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))), | ||
| SM, LangOpts) | ||
| .isInvalid()) | ||
| return {StartLoc}; | ||
| return {StartLoc, EndLoc, ClosingInsertion}; | ||
| } | ||
|
|
||
| } // namespace clang::tidy::utils |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| //===--- BracesAroundStatement.h - clang-tidy ------- -----------*- 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| /// | ||
| /// \file | ||
| /// This file provides utilities to put braces around a statement. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "clang/AST/Stmt.h" | ||
| #include "clang/Basic/Diagnostic.h" | ||
| #include "clang/Basic/SourceLocation.h" | ||
| #include "clang/Basic/SourceManager.h" | ||
|
|
||
| namespace clang::tidy::utils { | ||
|
|
||
| /// A provider of fix-it hints to insert opening and closing braces. An instance | ||
| /// of this type is the result of calling `getBraceInsertionsHints` below. | ||
| struct BraceInsertionHints { | ||
| /// The position of a potential diagnostic. It coincides with the position of | ||
| /// the opening brace to insert, but can also just be the place to show a | ||
| /// diagnostic in case braces cannot be inserted automatically. | ||
| SourceLocation DiagnosticPos; | ||
|
|
||
| /// Constructor for a no-hint. | ||
| BraceInsertionHints() = default; | ||
|
|
||
| /// Constructor for a valid hint that cannot insert braces automatically. | ||
| BraceInsertionHints(SourceLocation DiagnosticPos) | ||
| : DiagnosticPos(DiagnosticPos) {} | ||
|
|
||
| /// Constructor for a hint offering fix-its for brace insertion. Both | ||
| /// positions must be valid. | ||
| BraceInsertionHints(SourceLocation OpeningBracePos, | ||
| SourceLocation ClosingBracePos, std::string ClosingBrace) | ||
| : DiagnosticPos(OpeningBracePos), OpeningBracePos(OpeningBracePos), | ||
| ClosingBracePos(ClosingBracePos), ClosingBrace(ClosingBrace) { | ||
| assert(offersFixIts()); | ||
| } | ||
|
|
||
| /// Indicates whether the hint provides at least the position of a diagnostic. | ||
| operator bool() const; | ||
|
|
||
| /// Indicates whether the hint provides fix-its to insert braces. | ||
| bool offersFixIts() const; | ||
|
|
||
| /// The number of lines between the inserted opening brace and its closing | ||
| /// counterpart. | ||
| unsigned resultingCompoundLineExtent(const SourceManager &SourceMgr) const; | ||
|
|
||
| /// Fix-it to insert an opening brace. | ||
| FixItHint openingBraceFixIt() const; | ||
|
|
||
| /// Fix-it to insert a closing brace. | ||
| FixItHint closingBraceFixIt() const; | ||
|
|
||
| private: | ||
| SourceLocation OpeningBracePos; | ||
| SourceLocation ClosingBracePos; | ||
| std::string ClosingBrace; | ||
| }; | ||
|
|
||
| /// Create fix-it hints for braces that wrap the given statement when applied. | ||
| /// The algorithm computing them respects comment before and after the statement | ||
| /// and adds line breaks before the braces accordingly. | ||
| BraceInsertionHints | ||
| getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts, | ||
| const SourceManager &SM, SourceLocation StartLoc, | ||
| SourceLocation EndLocHint = SourceLocation()); | ||
|
|
||
| } // namespace clang::tidy::utils |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,224 @@ | ||
| //===--- SemaBase.h - Common utilities for semantic analysis-----*- 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 the SemaBase class, which provides utilities for Sema | ||
| // and its parts like SemaOpenACC. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_CLANG_SEMA_SEMABASE_H | ||
| #define LLVM_CLANG_SEMA_SEMABASE_H | ||
|
|
||
| #include "clang/AST/Decl.h" | ||
| #include "clang/AST/Redeclarable.h" | ||
| #include "clang/Basic/Diagnostic.h" | ||
| #include "clang/Basic/PartialDiagnostic.h" | ||
| #include "clang/Basic/SourceLocation.h" | ||
| #include "clang/Sema/Ownership.h" | ||
| #include "llvm/ADT/DenseMap.h" | ||
| #include <optional> | ||
| #include <type_traits> | ||
| #include <utility> | ||
| #include <vector> | ||
|
|
||
| namespace clang { | ||
|
|
||
| class ASTContext; | ||
| class DiagnosticsEngine; | ||
| class LangOptions; | ||
| class Sema; | ||
|
|
||
| class SemaBase { | ||
| public: | ||
| SemaBase(Sema &S); | ||
|
|
||
| Sema &SemaRef; | ||
|
|
||
| ASTContext &getASTContext() const; | ||
| DiagnosticsEngine &getDiagnostics() const; | ||
| const LangOptions &getLangOpts() const; | ||
|
|
||
| /// Helper class that creates diagnostics with optional | ||
| /// template instantiation stacks. | ||
| /// | ||
| /// This class provides a wrapper around the basic DiagnosticBuilder | ||
| /// class that emits diagnostics. ImmediateDiagBuilder is | ||
| /// responsible for emitting the diagnostic (as DiagnosticBuilder | ||
| /// does) and, if the diagnostic comes from inside a template | ||
| /// instantiation, printing the template instantiation stack as | ||
| /// well. | ||
| class ImmediateDiagBuilder : public DiagnosticBuilder { | ||
| Sema &SemaRef; | ||
| unsigned DiagID; | ||
|
|
||
| public: | ||
| ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) | ||
| : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} | ||
| ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) | ||
| : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} | ||
|
|
||
| // This is a cunning lie. DiagnosticBuilder actually performs move | ||
| // construction in its copy constructor (but due to varied uses, it's not | ||
| // possible to conveniently express this as actual move construction). So | ||
| // the default copy ctor here is fine, because the base class disables the | ||
| // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op | ||
| // in that case anwyay. | ||
| ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; | ||
|
|
||
| ~ImmediateDiagBuilder(); | ||
|
|
||
| /// Teach operator<< to produce an object of the correct type. | ||
| template <typename T> | ||
| friend const ImmediateDiagBuilder & | ||
| operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { | ||
| const DiagnosticBuilder &BaseDiag = Diag; | ||
| BaseDiag << Value; | ||
| return Diag; | ||
| } | ||
|
|
||
| // It is necessary to limit this to rvalue reference to avoid calling this | ||
| // function with a bitfield lvalue argument since non-const reference to | ||
| // bitfield is not allowed. | ||
| template <typename T, | ||
| typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>> | ||
| const ImmediateDiagBuilder &operator<<(T &&V) const { | ||
| const DiagnosticBuilder &BaseDiag = *this; | ||
| BaseDiag << std::move(V); | ||
| return *this; | ||
| } | ||
| }; | ||
|
|
||
| /// A generic diagnostic builder for errors which may or may not be deferred. | ||
| /// | ||
| /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) | ||
| /// which are not allowed to appear inside __device__ functions and are | ||
| /// allowed to appear in __host__ __device__ functions only if the host+device | ||
| /// function is never codegen'ed. | ||
| /// | ||
| /// To handle this, we use the notion of "deferred diagnostics", where we | ||
| /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. | ||
| /// | ||
| /// This class lets you emit either a regular diagnostic, a deferred | ||
| /// diagnostic, or no diagnostic at all, according to an argument you pass to | ||
| /// its constructor, thus simplifying the process of creating these "maybe | ||
| /// deferred" diagnostics. | ||
| class SemaDiagnosticBuilder { | ||
| public: | ||
| enum Kind { | ||
| /// Emit no diagnostics. | ||
| K_Nop, | ||
| /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). | ||
| K_Immediate, | ||
| /// Emit the diagnostic immediately, and, if it's a warning or error, also | ||
| /// emit a call stack showing how this function can be reached by an a | ||
| /// priori known-emitted function. | ||
| K_ImmediateWithCallStack, | ||
| /// Create a deferred diagnostic, which is emitted only if the function | ||
| /// it's attached to is codegen'ed. Also emit a call stack as with | ||
| /// K_ImmediateWithCallStack. | ||
| K_Deferred | ||
| }; | ||
|
|
||
| SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, | ||
| const FunctionDecl *Fn, Sema &S); | ||
| SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); | ||
| SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; | ||
|
|
||
| // The copy and move assignment operator is defined as deleted pending | ||
| // further motivation. | ||
| SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete; | ||
| SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete; | ||
|
|
||
| ~SemaDiagnosticBuilder(); | ||
|
|
||
| bool isImmediate() const { return ImmediateDiag.has_value(); } | ||
|
|
||
| /// Convertible to bool: True if we immediately emitted an error, false if | ||
| /// we didn't emit an error or we created a deferred error. | ||
| /// | ||
| /// Example usage: | ||
| /// | ||
| /// if (SemaDiagnosticBuilder(...) << foo << bar) | ||
| /// return ExprError(); | ||
| /// | ||
| /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably | ||
| /// want to use these instead of creating a SemaDiagnosticBuilder yourself. | ||
| operator bool() const { return isImmediate(); } | ||
|
|
||
| template <typename T> | ||
| friend const SemaDiagnosticBuilder & | ||
| operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { | ||
| if (Diag.ImmediateDiag) | ||
| *Diag.ImmediateDiag << Value; | ||
| else if (Diag.PartialDiagId) | ||
| Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second | ||
| << Value; | ||
| return Diag; | ||
| } | ||
|
|
||
| // It is necessary to limit this to rvalue reference to avoid calling this | ||
| // function with a bitfield lvalue argument since non-const reference to | ||
| // bitfield is not allowed. | ||
| template <typename T, | ||
| typename = std::enable_if_t<!std::is_lvalue_reference<T>::value>> | ||
| const SemaDiagnosticBuilder &operator<<(T &&V) const { | ||
| if (ImmediateDiag) | ||
| *ImmediateDiag << std::move(V); | ||
| else if (PartialDiagId) | ||
| getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V); | ||
| return *this; | ||
| } | ||
|
|
||
| friend const SemaDiagnosticBuilder & | ||
| operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD); | ||
|
|
||
| void AddFixItHint(const FixItHint &Hint) const; | ||
|
|
||
| friend ExprResult ExprError(const SemaDiagnosticBuilder &) { | ||
| return ExprError(); | ||
| } | ||
| friend StmtResult StmtError(const SemaDiagnosticBuilder &) { | ||
| return StmtError(); | ||
| } | ||
| operator ExprResult() const { return ExprError(); } | ||
| operator StmtResult() const { return StmtError(); } | ||
| operator TypeResult() const { return TypeError(); } | ||
| operator DeclResult() const { return DeclResult(true); } | ||
| operator MemInitResult() const { return MemInitResult(true); } | ||
|
|
||
| using DeferredDiagnosticsType = | ||
| llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>, | ||
| std::vector<PartialDiagnosticAt>>; | ||
|
|
||
| private: | ||
| Sema &S; | ||
| SourceLocation Loc; | ||
| unsigned DiagID; | ||
| const FunctionDecl *Fn; | ||
| bool ShowCallStack; | ||
|
|
||
| // Invariant: At most one of these Optionals has a value. | ||
| // FIXME: Switch these to a Variant once that exists. | ||
| std::optional<ImmediateDiagBuilder> ImmediateDiag; | ||
| std::optional<unsigned> PartialDiagId; | ||
|
|
||
| DeferredDiagnosticsType &getDeviceDeferredDiags() const; | ||
| }; | ||
|
|
||
| /// Emit a diagnostic. | ||
| SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, | ||
| bool DeferHint = false); | ||
|
|
||
| /// Emit a partial diagnostic. | ||
| SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, | ||
| bool DeferHint = false); | ||
| }; | ||
|
|
||
| } // namespace clang | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| #include "clang/Sema/SemaBase.h" | ||
| #include "clang/Sema/Sema.h" | ||
|
|
||
| namespace clang { | ||
|
|
||
| SemaBase::SemaBase(Sema &S) : SemaRef(S) {} | ||
|
|
||
| ASTContext &SemaBase::getASTContext() const { return SemaRef.Context; } | ||
| DiagnosticsEngine &SemaBase::getDiagnostics() const { return SemaRef.Diags; } | ||
| const LangOptions &SemaBase::getLangOpts() const { return SemaRef.LangOpts; } | ||
|
|
||
| SemaBase::ImmediateDiagBuilder::~ImmediateDiagBuilder() { | ||
| // If we aren't active, there is nothing to do. | ||
| if (!isActive()) | ||
| return; | ||
|
|
||
| // Otherwise, we need to emit the diagnostic. First clear the diagnostic | ||
| // builder itself so it won't emit the diagnostic in its own destructor. | ||
| // | ||
| // This seems wasteful, in that as written the DiagnosticBuilder dtor will | ||
| // do its own needless checks to see if the diagnostic needs to be | ||
| // emitted. However, because we take care to ensure that the builder | ||
| // objects never escape, a sufficiently smart compiler will be able to | ||
| // eliminate that code. | ||
| Clear(); | ||
|
|
||
| // Dispatch to Sema to emit the diagnostic. | ||
| SemaRef.EmitCurrentDiagnostic(DiagID); | ||
| } | ||
|
|
||
| const SemaBase::SemaDiagnosticBuilder & | ||
| operator<<(const SemaBase::SemaDiagnosticBuilder &Diag, | ||
| const PartialDiagnostic &PD) { | ||
| if (Diag.ImmediateDiag) | ||
| PD.Emit(*Diag.ImmediateDiag); | ||
| else if (Diag.PartialDiagId) | ||
| Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; | ||
| return Diag; | ||
| } | ||
|
|
||
| void SemaBase::SemaDiagnosticBuilder::AddFixItHint( | ||
| const FixItHint &Hint) const { | ||
| if (ImmediateDiag) | ||
| ImmediateDiag->AddFixItHint(Hint); | ||
| else if (PartialDiagId) | ||
| S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); | ||
| } | ||
|
|
||
| llvm::DenseMap<CanonicalDeclPtr<const FunctionDecl>, | ||
| std::vector<PartialDiagnosticAt>> & | ||
| SemaBase::SemaDiagnosticBuilder::getDeviceDeferredDiags() const { | ||
| return S.DeviceDeferredDiags; | ||
| } | ||
|
|
||
| Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, unsigned DiagID, | ||
| bool DeferHint) { | ||
| bool IsError = | ||
| getDiagnostics().getDiagnosticIDs()->isDefaultMappingAsError(DiagID); | ||
| bool ShouldDefer = getLangOpts().CUDA && getLangOpts().GPUDeferDiag && | ||
| DiagnosticIDs::isDeferrable(DiagID) && | ||
| (DeferHint || SemaRef.DeferDiags || !IsError); | ||
| auto SetIsLastErrorImmediate = [&](bool Flag) { | ||
| if (IsError) | ||
| SemaRef.IsLastErrorImmediate = Flag; | ||
| }; | ||
| if (!ShouldDefer) { | ||
| SetIsLastErrorImmediate(true); | ||
| return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, | ||
| DiagID, SemaRef.getCurFunctionDecl(), SemaRef); | ||
| } | ||
|
|
||
| SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice | ||
| ? SemaRef.CUDADiagIfDeviceCode(Loc, DiagID) | ||
| : SemaRef.CUDADiagIfHostCode(Loc, DiagID); | ||
| SetIsLastErrorImmediate(DB.isImmediate()); | ||
| return DB; | ||
| } | ||
|
|
||
| Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, | ||
| const PartialDiagnostic &PD, | ||
| bool DeferHint) { | ||
| return Diag(Loc, PD.getDiagID(), DeferHint) << PD; | ||
| } | ||
|
|
||
| } // namespace clang |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| // RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
| // RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK | ||
|
|
||
| #if __cplusplus == 199711L | ||
| #define NOTHROW throw() | ||
| #else | ||
| #define NOTHROW noexcept(true) | ||
| #endif | ||
|
|
||
| namespace dr392 { // dr392: 2.8 | ||
|
|
||
| struct A { | ||
| operator bool() NOTHROW; | ||
| }; | ||
|
|
||
| class C { | ||
| public: | ||
| C() NOTHROW; | ||
| ~C() NOTHROW; | ||
| A& get() NOTHROW { return p; } | ||
| private: | ||
| A p; | ||
| }; | ||
|
|
||
| void f() | ||
| { | ||
| if (C().get()) {} | ||
| } | ||
|
|
||
| } // namespace dr392 | ||
|
|
||
| // CHECK-LABEL: define {{.*}} void @dr392::f()() | ||
| // CHECK: call {{.*}} i1 @dr392::A::operator bool() | ||
| // CHECK: call void @dr392::C::~C() | ||
| // CHECK-LABEL: } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,5 +3,5 @@ add_libc_fuzzer( | |
| SRCS | ||
| uint_fuzz.cpp | ||
| DEPENDS | ||
| libc.src.__support.big_int | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| #include <algorithm> | ||
| #include <cassert> | ||
|
|
||
| #include <benchmark/benchmark.h> | ||
|
|
||
| void run_sizes(auto benchmark) { | ||
| benchmark->Arg(1) | ||
| ->Arg(2) | ||
| ->Arg(3) | ||
| ->Arg(4) | ||
| ->Arg(5) | ||
| ->Arg(6) | ||
| ->Arg(7) | ||
| ->Arg(8) | ||
| ->Arg(9) | ||
| ->Arg(10) | ||
| ->Arg(11) | ||
| ->Arg(12) | ||
| ->Arg(13) | ||
| ->Arg(14) | ||
| ->Arg(15) | ||
| ->Arg(16) | ||
| ->Arg(17) | ||
| ->Arg(18) | ||
| ->Arg(19) | ||
| ->Arg(20) | ||
| ->Arg(21) | ||
| ->Arg(22) | ||
| ->Arg(23) | ||
| ->Arg(24) | ||
| ->Arg(25) | ||
| ->Arg(26) | ||
| ->Arg(27) | ||
| ->Arg(28) | ||
| ->Arg(29) | ||
| ->Arg(30) | ||
| ->Arg(31) | ||
| ->Arg(32) | ||
| ->Arg(64) | ||
| ->Arg(512) | ||
| ->Arg(1024) | ||
| ->Arg(4000) | ||
| ->Arg(4096) | ||
| ->Arg(5500) | ||
| ->Arg(64000) | ||
| ->Arg(65536) | ||
| ->Arg(70000); | ||
| } | ||
|
|
||
| template <class T> | ||
| static void BM_std_minmax(benchmark::State& state) { | ||
| std::vector<T> vec(state.range(), 3); | ||
|
|
||
| for (auto _ : state) { | ||
| benchmark::DoNotOptimize(vec); | ||
| benchmark::DoNotOptimize(std::ranges::minmax(vec)); | ||
| } | ||
| } | ||
| BENCHMARK(BM_std_minmax<char>)->Apply(run_sizes); | ||
| BENCHMARK(BM_std_minmax<short>)->Apply(run_sizes); | ||
| BENCHMARK(BM_std_minmax<int>)->Apply(run_sizes); | ||
| BENCHMARK(BM_std_minmax<long long>)->Apply(run_sizes); | ||
| BENCHMARK(BM_std_minmax<unsigned char>)->Apply(run_sizes); | ||
| BENCHMARK(BM_std_minmax<unsigned short>)->Apply(run_sizes); | ||
| BENCHMARK(BM_std_minmax<unsigned int>)->Apply(run_sizes); | ||
| BENCHMARK(BM_std_minmax<unsigned long long>)->Apply(run_sizes); | ||
|
|
||
| BENCHMARK_MAIN(); |