Skip to content

Commit

Permalink
merge main into amd-staging
Browse files Browse the repository at this point in the history
Change-Id: I3f22ab5402113df190587c26aa5dcc8b370cbb35
  • Loading branch information
Jenkins committed Dec 18, 2024
2 parents 113585a + b1f4a02 commit 71c0fd4
Show file tree
Hide file tree
Showing 281 changed files with 15,827 additions and 12,364 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ jobs:
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: 'llvm/docs/requirements.txt'
cache-dependency-path: 'llvm/docs/requirements-hashed.txt'
- name: Install python dependencies
run: pip install -r llvm/docs/requirements.txt
run: pip install -r llvm/docs/requirements-hashed.txt
- name: Install system dependencies
run: |
sudo apt-get update
Expand Down
136 changes: 136 additions & 0 deletions clang-tools-extra/test/clang-doc/builtin_types.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t/yaml %t/md

// RUN: clang-doc --doxygen --executor=standalone %s -output=%t/yaml
// RUN: FileCheck %s < %t/yaml/index.yaml --check-prefix=YAML

// RUN: clang-doc --doxygen --executor=standalone %s -output=%t/md --format=md
// RUN: FileCheck %s < %t/md/GlobalNamespace/index.md --check-prefix=MD

// YAML: ---
// YAML-NEXT: USR: '0000000000000000000000000000000000000000'
// YAML-NEXT: ChildFunctions:

// MD: # Global Namespace
// MD: ## Functions

extern bool b();

// YAML-NEXT: - USR: '88A104C263241E354ECF5B55B04AE8CEAD625B71'
// YAML-NEXT: Name: 'b'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: '_Bool'
// YAML-NEXT: QualName: '_Bool'

// MD: ### b
// MD: *_Bool b()*

char c();

// YAML-NEXT: - USR: 'EA3287837B3F175C8DB154406B4DAD2924F479B5'
// YAML-NEXT: Name: 'c'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: 'char'
// YAML-NEXT: QualName: 'char'

// MD: ### c
// MD: *char c()*

double d();

// YAML-NEXT: - USR: '60A47E4696CEFC411AB2E1EEFA2DD914E2A7E450'
// YAML-NEXT: Name: 'd'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: 'double'
// YAML-NEXT: QualName: 'double'

// MD: ### d
// MD: *double d()*

float f();

// YAML-NEXT: - USR: 'B3A9EC6BECD5869CF3ACDFB25153CFE6BBDD5EAB'
// YAML-NEXT: Name: 'f'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: 'float'
// YAML-NEXT: QualName: 'float'

// MD: ### f
// MD: *float f()*

int i();

// YAML-NEXT: - USR: '307041280A81EB46F949A94AD52587C659FD801C'
// YAML-NEXT: Name: 'i'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: 'int'
// YAML-NEXT: QualName: 'int'

// MD: ### i
// MD: *int i()*

long l();

// YAML-NEXT: - USR: 'A1CE9AB0064C412F857592E01332C641C1A06F37'
// YAML-NEXT: Name: 'l'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: 'long'
// YAML-NEXT: QualName: 'long'

// MD: ### l
// MD: *long l()*

long long ll();

// YAML-NEXT: - USR: '5C2C44ED4825C066EF6ED796863586F343C8BCA9'
// YAML-NEXT: Name: 'll'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: 'long long'
// YAML-NEXT: QualName: 'long long'

// MD: ### ll
// MD: *long long ll()*

short s();

// YAML-NEXT: - USR: '412341570FD3AD2C3A1E9A1DE7B3C01C07BEACFE'
// YAML-NEXT: Name: 's'
// YAML-NEXT: Location:
// YAML-NEXT: - LineNumber: [[# @LINE-5]]
// YAML-NEXT: Filename: '{{.*}}'
// YAML-NEXT: ReturnType:
// YAML-NEXT: Type:
// YAML-NEXT: Name: 'short'
// YAML-NEXT: QualName: 'short'
// YAML-NEXT: ...

// MD: ### s
// MD: *short s()*
10 changes: 10 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,16 @@ Improvements to Clang's diagnostics
views.push_back(std::string("123")); // warning
}

- Clang now emits a ``-Wtautological-compare`` diagnostic when a check for
pointer addition overflow is always true or false, because overflow would
be undefined behavior.

.. code-block:: c++

bool incorrect_overflow_check(const char *ptr, size_t index) {
return ptr + index < ptr; // warning
}
Improvements to Clang's time-trace
----------------------------------

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10249,7 +10249,7 @@ def warn_dangling_reference_captured_by_unknown : Warning<
// should result in a warning, since these always evaluate to a constant.
// Array comparisons have similar warnings
def warn_comparison_always : Warning<
"%select{self-|array }0comparison always evaluates to "
"%select{self-|array |pointer }0comparison always evaluates to "
"%select{a constant|true|false|'std::strong_ordering::equal'}1">,
InGroup<TautologicalCompare>;
def warn_comparison_bitwise_always : Warning<
Expand Down
127 changes: 62 additions & 65 deletions clang/lib/Driver/SanitizerArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,48 +248,76 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) {
return Kinds;
}

// Computes the sanitizer mask based on the default plus opt-in (if supported)
// minus opt-out.
// Computes the sanitizer mask as:
// Default + Arguments (in or out)
// with arguments parsed from left to right.
//
// Error messages are printed if the AlwaysIn or AlwaysOut invariants are
// violated, but the caller must enforce these invariants themselves.
static SanitizerMask
parseSanitizeArgs(const Driver &D, const llvm::opt::ArgList &Args,
bool DiagnoseErrors, SanitizerMask Supported,
SanitizerMask Default, int OptInID, int OptOutID) {
SanitizerMask Remove; // During the loop below, the accumulated set of
// sanitizers disabled by the current sanitizer
// argument or any argument after it.
SanitizerMask Kinds;
SanitizerMask SupportedWithGroups = setGroupBits(Supported);

for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) {
bool DiagnoseErrors, SanitizerMask Default,
SanitizerMask AlwaysIn, SanitizerMask AlwaysOut, int OptInID,
int OptOutID) {
assert(!(AlwaysIn & AlwaysOut) &&
"parseSanitizeArgs called with contradictory in/out requirements");

SanitizerMask Output = Default;
// Keep track of which violations we have already reported, to avoid
// duplicate error messages.
SanitizerMask DiagnosedAlwaysInViolations;
SanitizerMask DiagnosedAlwaysOutViolations;
for (const auto *Arg : Args) {
if (Arg->getOption().matches(OptInID)) {
Arg->claim();
SanitizerMask Add = parseArgValues(D, Arg, true);
Add &= ~Remove;
SanitizerMask InvalidValues = Add & ~SupportedWithGroups;
if (InvalidValues && DiagnoseErrors) {
SanitizerSet S;
S.Mask = InvalidValues;
D.Diag(diag::err_drv_unsupported_option_argument)
<< Arg->getSpelling() << toString(S);
SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
// Report error if user explicitly tries to opt-in to an always-out
// sanitizer.
if (SanitizerMask KindsToDiagnose =
Add & AlwaysOut & ~DiagnosedAlwaysOutViolations) {
if (DiagnoseErrors) {
SanitizerSet SetToDiagnose;
SetToDiagnose.Mask |= KindsToDiagnose;
D.Diag(diag::err_drv_unsupported_option_argument)
<< Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedAlwaysOutViolations |= KindsToDiagnose;
}
}
Kinds |= expandSanitizerGroups(Add) & ~Remove;
Output |= expandSanitizerGroups(Add);
Arg->claim();
} else if (Arg->getOption().matches(OptOutID)) {
SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
// Report error if user explicitly tries to opt-out of an always-in
// sanitizer.
if (SanitizerMask KindsToDiagnose =
Remove & AlwaysIn & ~DiagnosedAlwaysInViolations) {
if (DiagnoseErrors) {
SanitizerSet SetToDiagnose;
SetToDiagnose.Mask |= KindsToDiagnose;
D.Diag(diag::err_drv_unsupported_option_argument)
<< Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedAlwaysInViolations |= KindsToDiagnose;
}
}
Output &= ~expandSanitizerGroups(Remove);
Arg->claim();
Remove |= expandSanitizerGroups(parseArgValues(D, Arg, DiagnoseErrors));
}
}

// Apply default behavior.
Kinds |= Default & ~Remove;

return Kinds;
return Output;
}

static SanitizerMask parseSanitizeTrapArgs(const Driver &D,
const llvm::opt::ArgList &Args,
bool DiagnoseErrors) {
return parseSanitizeArgs(D, Args, DiagnoseErrors, TrappingSupported,
TrappingDefault, options::OPT_fsanitize_trap_EQ,
SanitizerMask AlwaysTrap; // Empty
SanitizerMask NeverTrap = ~(setGroupBits(TrappingSupported));

// N.B. We do *not* enforce NeverTrap. This maintains the behavior of
// '-fsanitize=undefined -fsanitize-trap=undefined'
// (clang/test/Driver/fsanitize.c ), which is that vptr is not enabled at all
// (not even in recover mode) in order to avoid the need for a ubsan runtime.
return parseSanitizeArgs(D, Args, DiagnoseErrors, TrappingDefault, AlwaysTrap,
NeverTrap, options::OPT_fsanitize_trap_EQ,
options::OPT_fno_sanitize_trap_EQ);
}

Expand Down Expand Up @@ -657,44 +685,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
// default in ASan?

// Parse -f(no-)?sanitize-recover flags.
SanitizerMask RecoverableKinds = RecoverableByDefault | AlwaysRecoverable;
SanitizerMask DiagnosedUnrecoverableKinds;
SanitizerMask DiagnosedAlwaysRecoverableKinds;
for (const auto *Arg : Args) {
if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) {
SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors);
// Report error if user explicitly tries to recover from unrecoverable
// sanitizer.
if (SanitizerMask KindsToDiagnose =
Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) {
SanitizerSet SetToDiagnose;
SetToDiagnose.Mask |= KindsToDiagnose;
if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
<< Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedUnrecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds |= expandSanitizerGroups(Add);
Arg->claim();
} else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) {
SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors);
// Report error if user explicitly tries to disable recovery from
// always recoverable sanitizer.
if (SanitizerMask KindsToDiagnose =
Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) {
SanitizerSet SetToDiagnose;
SetToDiagnose.Mask |= KindsToDiagnose;
if (DiagnoseErrors)
D.Diag(diag::err_drv_unsupported_option_argument)
<< Arg->getSpelling() << toString(SetToDiagnose);
DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose;
}
RecoverableKinds &= ~expandSanitizerGroups(Remove);
Arg->claim();
}
}
RecoverableKinds &= Kinds;
SanitizerMask RecoverableKinds = parseSanitizeArgs(
D, Args, DiagnoseErrors, RecoverableByDefault, AlwaysRecoverable,
Unrecoverable, options::OPT_fsanitize_recover_EQ,
options::OPT_fno_sanitize_recover_EQ);
RecoverableKinds |= AlwaysRecoverable;
RecoverableKinds &= ~Unrecoverable;
RecoverableKinds &= Kinds;

TrappingKinds &= Kinds;
RecoverableKinds &= ~TrappingKinds;
Expand Down
50 changes: 50 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11786,6 +11786,50 @@ static bool checkForArray(const Expr *E) {
return D->getType()->isArrayType() && !D->isWeak();
}

/// Detect patterns ptr + size >= ptr and ptr + size < ptr, where ptr is a
/// pointer and size is an unsigned integer. Return whether the result is
/// always true/false.
static std::optional<bool> isTautologicalBoundsCheck(const Expr *LHS,
const Expr *RHS,
BinaryOperatorKind Opc) {
if (!LHS->getType()->isPointerType())
return std::nullopt;

// Canonicalize to >= or < predicate.
switch (Opc) {
case BO_GE:
case BO_LT:
break;
case BO_GT:
std::swap(LHS, RHS);
Opc = BO_LT;
break;
case BO_LE:
std::swap(LHS, RHS);
Opc = BO_GE;
break;
default:
return std::nullopt;
}

auto *BO = dyn_cast<BinaryOperator>(LHS);
if (!BO || BO->getOpcode() != BO_Add)
return std::nullopt;

Expr *Other;
if (Expr::isSameComparisonOperand(BO->getLHS(), RHS))
Other = BO->getRHS();
else if (Expr::isSameComparisonOperand(BO->getRHS(), RHS))
Other = BO->getLHS();
else
return std::nullopt;

if (!Other->getType()->isUnsignedIntegerType())
return std::nullopt;

return Opc == BO_GE;
}

/// Diagnose some forms of syntactically-obvious tautological comparison.
static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS,
Expand Down Expand Up @@ -11895,6 +11939,12 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc,
S.PDiag(diag::warn_comparison_always)
<< 1 /*array comparison*/
<< Result);
} else if (std::optional<bool> Res =
isTautologicalBoundsCheck(LHS, RHS, Opc)) {
S.DiagRuntimeBehavior(Loc, nullptr,
S.PDiag(diag::warn_comparison_always)
<< 2 /*pointer comparison*/
<< (*Res ? AlwaysTrue : AlwaysFalse));
}
}

Expand Down
Loading

0 comments on commit 71c0fd4

Please sign in to comment.