14 changes: 12 additions & 2 deletions bolt/test/X86/dwarf5-types-debug-names.test
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@

; BOLT: Name Index @ 0x0 {
; BOLT: Header {
; BOLT: Length: 0xE1
; BOLT: Length: 0xE9
; BOLT: Format: DWARF32
; BOLT: Version: 5
; BOLT: CU count: 2
; BOLT: Local TU count: 1
; BOLT: Foreign TU count: 0
; BOLT: Bucket count: 6
; BOLT: Name count: 6
; BOLT: Abbreviations table size: 0x21
; BOLT: Abbreviations table size: 0x29
; BOLT: Augmentation: 'BOLT'
; BOLT: }
; BOLT: Compilation Unit offsets [
Expand All @@ -37,21 +37,25 @@
; BOLT: Tag: DW_TAG_structure_type
; BOLT: DW_IDX_type_unit: DW_FORM_data1
; BOLT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT: DW_IDX_parent: DW_FORM_flag_present
; BOLT: }
; BOLT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
; BOLT: Tag: DW_TAG_subprogram
; BOLT: DW_IDX_compile_unit: DW_FORM_data1
; BOLT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT: DW_IDX_parent: DW_FORM_flag_present
; BOLT: }
; BOLT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
; BOLT: Tag: DW_TAG_base_type
; BOLT: DW_IDX_compile_unit: DW_FORM_data1
; BOLT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT: DW_IDX_parent: DW_FORM_flag_present
; BOLT: }
; BOLT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
; BOLT: Tag: DW_TAG_base_type
; BOLT: DW_IDX_type_unit: DW_FORM_data1
; BOLT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT: DW_IDX_parent: DW_FORM_flag_present
; BOLT: }
; BOLT: ]
; BOLT: Bucket 0 [
Expand All @@ -63,6 +67,7 @@
; BOLT: Tag: DW_TAG_structure_type
; BOLT: DW_IDX_type_unit: 0x00
; BOLT: DW_IDX_die_offset: 0x00000023
; BOLT: DW_IDX_parent: <parent not indexed>
; BOLT: }
; BOLT: }
; BOLT: ]
Expand All @@ -75,6 +80,7 @@
; BOLT: Tag: DW_TAG_subprogram
; BOLT: DW_IDX_compile_unit: 0x01
; BOLT: DW_IDX_die_offset: 0x00000024
; BOLT: DW_IDX_parent: <parent not indexed>
; BOLT: }
; BOLT: }
; BOLT: ]
Expand All @@ -87,6 +93,7 @@
; BOLT: Tag: DW_TAG_base_type
; BOLT: DW_IDX_compile_unit: 0x01
; BOLT: DW_IDX_die_offset: 0x00000040
; BOLT: DW_IDX_parent: <parent not indexed>
; BOLT: }
; BOLT: }
; BOLT: ]
Expand All @@ -99,6 +106,7 @@
; BOLT: Tag: DW_TAG_subprogram
; BOLT: DW_IDX_compile_unit: 0x01
; BOLT: DW_IDX_die_offset: 0x00000024
; BOLT: DW_IDX_parent: <parent not indexed>
; BOLT: }
; BOLT: }
; BOLT: ]
Expand All @@ -111,6 +119,7 @@
; BOLT: Tag: DW_TAG_subprogram
; BOLT: DW_IDX_compile_unit: 0x00
; BOLT: DW_IDX_die_offset: 0x00000024
; BOLT: DW_IDX_parent: <parent not indexed>
; BOLT: }
; BOLT: }
; BOLT: ]
Expand All @@ -123,6 +132,7 @@
; BOLT: Tag: DW_TAG_base_type
; BOLT: DW_IDX_type_unit: 0x00
; BOLT: DW_IDX_die_offset: 0x00000038
; BOLT: DW_IDX_parent: <parent not indexed>
; BOLT: }
; BOLT: }
; BOLT: ]
Expand Down
12 changes: 10 additions & 2 deletions bolt/test/X86/dwarf5-types-one-cu-debug-names.test
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@

; BOLT:Name Index @ 0x0 {
; BOLT-NEXT: Header {
; BOLT-NEXT: Length: 0xA3
; BOLT-NEXT: Length: 0xAB
; BOLT-NEXT: Format: DWARF32
; BOLT-NEXT: Version: 5
; BOLT-NEXT: CU count: 1
; BOLT-NEXT: Local TU count: 1
; BOLT-NEXT: Foreign TU count: 0
; BOLT-NEXT: Bucket count: 4
; BOLT-NEXT: Name count: 4
; BOLT-NEXT: Abbreviations table size: 0x1D
; BOLT-NEXT: Abbreviations table size: 0x25
; BOLT-NEXT: Augmentation: 'BOLT'
; BOLT-NEXT: }
; BOLT-NEXT: Compilation Unit offsets [
Expand All @@ -32,20 +32,24 @@
; BOLT-NEXT: Abbreviation [[ABBREV:0x[0-9a-f]*]] {
; BOLT-NEXT: Tag: DW_TAG_base_type
; BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; BOLT-NEXT: }
; BOLT-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] {
; BOLT-NEXT: Tag: DW_TAG_structure_type
; BOLT-NEXT: DW_IDX_type_unit: DW_FORM_data1
; BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; BOLT-NEXT: }
; BOLT-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] {
; BOLT-NEXT: Tag: DW_TAG_subprogram
; BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; BOLT-NEXT: }
; BOLT-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] {
; BOLT-NEXT: Tag: DW_TAG_base_type
; BOLT-NEXT: DW_IDX_type_unit: DW_FORM_data1
; BOLT-NEXT: DW_IDX_die_offset: DW_FORM_ref4
; BOLT-NEXT: DW_IDX_parent: DW_FORM_flag_present
; BOLT-NEXT: }
; BOLT-NEXT: ]
; BOLT-NEXT: Bucket 0 [
Expand All @@ -56,6 +60,7 @@
; BOLT-NEXT: Abbrev: [[ABBREV]]
; BOLT-NEXT: Tag: DW_TAG_base_type
; BOLT-NEXT: DW_IDX_die_offset: 0x0000003f
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
; BOLT-NEXT: }
; BOLT-NEXT: }
; BOLT-NEXT: Name 2 {
Expand All @@ -66,6 +71,7 @@
; BOLT-NEXT: Tag: DW_TAG_structure_type
; BOLT-NEXT: DW_IDX_type_unit: 0x00
; BOLT-NEXT: DW_IDX_die_offset: 0x00000023
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
; BOLT-NEXT: }
; BOLT-NEXT: }
; BOLT-NEXT: ]
Expand All @@ -80,6 +86,7 @@
; BOLT-NEXT: Abbrev: [[ABBREV2]]
; BOLT-NEXT: Tag: DW_TAG_subprogram
; BOLT-NEXT: DW_IDX_die_offset: 0x00000024
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
; BOLT-NEXT: }
; BOLT-NEXT: }
; BOLT-NEXT: ]
Expand All @@ -92,6 +99,7 @@
; BOLT-NEXT: Tag: DW_TAG_base_type
; BOLT-NEXT: DW_IDX_type_unit: 0x00
; BOLT-NEXT: DW_IDX_die_offset: 0x00000038
; BOLT-NEXT: DW_IDX_parent: <parent not indexed>
; BOLT-NEXT: }
; BOLT-NEXT: }
; BOLT-NEXT: ]
Expand Down
67 changes: 67 additions & 0 deletions bolt/test/X86/linux-static-keys.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# REQUIRES: system-linux

## Check that BOLT correctly updates the Linux kernel static keys jump table.

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \
# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr

## Verify static keys jump bindings to instructions.

# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 \
# RUN: --bolt-info=0 |& FileCheck %s

## Verify the bindings again on the rewritten binary with nops removed.

# RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized |& FileCheck %s

# CHECK: BOLT-INFO: Linux kernel binary detected
# CHECK: BOLT-INFO: parsed 2 static keys jump entries

.text
.globl _start
.type _start, %function
_start:
# CHECK: Binary Function "_start"
nop
.L0:
jmp .L1
# CHECK: jit
# CHECK-SAME: # ID: 1 {{.*}} # Likely: 0 # InitValue: 1
nop
.L1:
.nops 5
# CHECK: jit
# CHECK-SAME: # ID: 2 {{.*}} # Likely: 1 # InitValue: 1
.L2:
nop
.size _start, .-_start

.globl foo
.type foo, %function
foo:
ret
.size foo, .-foo


## Static keys jump table.
.rodata
.globl __start___jump_table
.type __start___jump_table, %object
__start___jump_table:

.long .L0 - . # Jump address
.long .L1 - . # Target address
.quad 1 # Key address

.long .L1 - . # Jump address
.long .L2 - . # Target address
.quad 0 # Key address

.globl __stop___jump_table
.type __stop___jump_table, %object
__stop___jump_table:

## Fake Linux Kernel sections.
.section __ksymtab,"a",@progbits
.section __ksymtab_gpl,"a",@progbits
4 changes: 4 additions & 0 deletions bolt/test/X86/reader-stale-yaml.test
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ RUN: --profile-ignore-hash=1 --profile-use-dfs=0 --debug-only=bolt-prof 2>&1 |
RUN: llvm-bolt %t.exe -o %t.null --b %p/Inputs/blarge_profile_stale.yaml \
RUN: --print-cfg --print-only=SolveCubic --infer-stale-profile=1 \
RUN: --profile-ignore-hash=1 --profile-use-dfs=0 --debug-only=bolt-prof 2>&1 | FileCheck %s -check-prefix=CHECK2
# Testing skipped function
RUN: llvm-bolt %t.exe -o %t.null --b %p/Inputs/blarge_profile_stale.yaml \
RUN: --print-cfg --print-only=usqrt --infer-stale-profile=1 --skip-funcs=usqrt \
RUN: --profile-ignore-hash=1 --profile-use-dfs=0

CHECK0: BOLT-INFO: 2 out of 7 functions in the binary (28.6%) have non-empty execution profile
CHECK0: BOLT-WARNING: 2 (100.0% of all profiled) functions have invalid (possibly stale) profile
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
#include "SuspiciousReallocUsageCheck.h"
#include "SuspiciousSemicolonCheck.h"
#include "SuspiciousStringCompareCheck.h"
#include "SuspiciousStringviewDataUsageCheck.h"
#include "SwappedArgumentsCheck.h"
#include "SwitchMissingDefaultCaseCheck.h"
#include "TerminatingContinueCheck.h"
Expand Down Expand Up @@ -218,6 +219,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-suspicious-semicolon");
CheckFactories.registerCheck<SuspiciousStringCompareCheck>(
"bugprone-suspicious-string-compare");
CheckFactories.registerCheck<SuspiciousStringviewDataUsageCheck>(
"bugprone-suspicious-stringview-data-usage");
CheckFactories.registerCheck<SwappedArgumentsCheck>(
"bugprone-swapped-arguments");
CheckFactories.registerCheck<TerminatingContinueCheck>(
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ add_clang_library(clangTidyBugproneModule
ImplicitWideningOfMultiplicationResultCheck.cpp
InaccurateEraseCheck.cpp
IncorrectEnableIfCheck.cpp
SuspiciousStringviewDataUsageCheck.cpp
SwitchMissingDefaultCaseCheck.cpp
IncDecInConditionsCheck.cpp
IncorrectRoundingsCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
//===--- SuspiciousStringviewDataUsageCheck.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
//
//===----------------------------------------------------------------------===//

#include "SuspiciousStringviewDataUsageCheck.h"
#include "../utils/Matchers.h"
#include "../utils/OptionsUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

using namespace clang::ast_matchers;

namespace clang::tidy::bugprone {

SuspiciousStringviewDataUsageCheck::SuspiciousStringviewDataUsageCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
StringViewTypes(utils::options::parseStringList(Options.get(
"StringViewTypes", "::std::basic_string_view;::llvm::StringRef"))),
AllowedCallees(
utils::options::parseStringList(Options.get("AllowedCallees", ""))) {}

void SuspiciousStringviewDataUsageCheck::storeOptions(
ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "StringViewTypes",
utils::options::serializeStringList(StringViewTypes));
Options.store(Opts, "AllowedCallees",
utils::options::serializeStringList(AllowedCallees));
}

bool SuspiciousStringviewDataUsageCheck::isLanguageVersionSupported(
const LangOptions &LangOpts) const {
return LangOpts.CPlusPlus;
}

std::optional<TraversalKind>
SuspiciousStringviewDataUsageCheck::getCheckTraversalKind() const {
return TK_AsIs;
}

void SuspiciousStringviewDataUsageCheck::registerMatchers(MatchFinder *Finder) {

auto AncestorCall = anyOf(
cxxConstructExpr(), callExpr(unless(cxxOperatorCallExpr())), lambdaExpr(),
initListExpr(
hasType(qualType(hasCanonicalType(hasDeclaration(recordDecl()))))));

auto DataMethod =
cxxMethodDecl(hasName("data"),
ofClass(matchers::matchesAnyListedName(StringViewTypes)));

auto SizeCall = cxxMemberCallExpr(
callee(cxxMethodDecl(hasAnyName("size", "length"))),
on(ignoringParenImpCasts(
matchers::isStatementIdenticalToBoundNode("self"))));

auto DescendantSizeCall = expr(hasDescendant(
expr(SizeCall, hasAncestor(expr(AncestorCall).bind("ancestor-size")),
hasAncestor(expr(equalsBoundNode("parent"),
equalsBoundNode("ancestor-size"))))));

Finder->addMatcher(
cxxMemberCallExpr(
on(ignoringParenImpCasts(expr().bind("self"))), callee(DataMethod),
expr().bind("data-call"),
hasParent(expr(anyOf(
invocation(
expr().bind("parent"), unless(cxxOperatorCallExpr()),
hasAnyArgument(
ignoringParenImpCasts(equalsBoundNode("data-call"))),
unless(hasAnyArgument(ignoringParenImpCasts(SizeCall))),
unless(hasAnyArgument(DescendantSizeCall)),
hasDeclaration(namedDecl(
unless(matchers::matchesAnyListedName(AllowedCallees))))),
initListExpr(expr().bind("parent"),
hasType(qualType(hasCanonicalType(hasDeclaration(
recordDecl(unless(matchers::matchesAnyListedName(
AllowedCallees))))))),
unless(DescendantSizeCall)))))),
this);
}

void SuspiciousStringviewDataUsageCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *DataCallExpr =
Result.Nodes.getNodeAs<CXXMemberCallExpr>("data-call");
diag(DataCallExpr->getExprLoc(),
"result of a `data()` call may not be null terminated, provide size "
"information to the callee to prevent potential issues")
<< DataCallExpr->getCallee()->getSourceRange();
}

} // namespace clang::tidy::bugprone
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===--- SuspiciousStringviewDataUsageCheck.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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGVIEWDATAUSAGECHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGVIEWDATAUSAGECHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::bugprone {

/// Identifies suspicious usages of std::string_view::data() that could lead to
/// reading out-of-bounds data due to inadequate or incorrect string null
/// termination.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/suspicious-stringview-data-usage.html
class SuspiciousStringviewDataUsageCheck : public ClangTidyCheck {
public:
SuspiciousStringviewDataUsageCheck(StringRef Name, ClangTidyContext *Context);
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
std::optional<TraversalKind> getCheckTraversalKind() const override;

private:
std::vector<llvm::StringRef> StringViewTypes;
std::vector<llvm::StringRef> AllowedCallees;
};

} // namespace clang::tidy::bugprone

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSSTRINGVIEWDATAUSAGECHECK_H
41 changes: 22 additions & 19 deletions clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,16 @@ AST_MATCHER_P(FunctionDecl, isInstantiatedFrom, Matcher<FunctionDecl>,
Finder, Builder);
}

AST_MATCHER_P(CXXMethodDecl, isOperatorOverloading,
llvm::SmallVector<OverloadedOperatorKind>, Kinds) {
return llvm::is_contained(Kinds, Node.getOverloadedOperator());
constexpr std::initializer_list<OverloadedOperatorKind>
AssignmentOverloadedOperatorKinds = {
OO_Equal, OO_PlusEqual, OO_MinusEqual, OO_StarEqual,
OO_SlashEqual, OO_PercentEqual, OO_CaretEqual, OO_AmpEqual,
OO_PipeEqual, OO_LessLessEqual, OO_GreaterGreaterEqual, OO_PlusPlus,
OO_MinusMinus};

AST_MATCHER(FunctionDecl, isAssignmentOverloadedOperator) {
return llvm::is_contained(AssignmentOverloadedOperatorKinds,
Node.getOverloadedOperator());
}
} // namespace

Expand Down Expand Up @@ -164,22 +171,18 @@ void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
}

void UnusedReturnValueCheck::registerMatchers(MatchFinder *Finder) {
auto MatchedDirectCallExpr = expr(
callExpr(
callee(functionDecl(
// Don't match void overloads of checked functions.
unless(returns(voidType())),
// Don't match copy or move assignment operator.
unless(cxxMethodDecl(isOperatorOverloading(
{OO_Equal, OO_PlusEqual, OO_MinusEqual, OO_StarEqual,
OO_SlashEqual, OO_PercentEqual, OO_CaretEqual, OO_AmpEqual,
OO_PipeEqual, OO_LessLessEqual, OO_GreaterGreaterEqual}))),
anyOf(
isInstantiatedFrom(
matchers::matchesAnyListedName(CheckedFunctions)),
returns(hasCanonicalType(hasDeclaration(namedDecl(
matchers::matchesAnyListedName(CheckedReturnTypes)))))))))
.bind("match"));
auto MatchedDirectCallExpr =
expr(callExpr(callee(functionDecl(
// Don't match copy or move assignment operator.
unless(isAssignmentOverloadedOperator()),
// Don't match void overloads of checked functions.
unless(returns(voidType())),
anyOf(isInstantiatedFrom(matchers::matchesAnyListedName(
CheckedFunctions)),
returns(hasCanonicalType(hasDeclaration(
namedDecl(matchers::matchesAnyListedName(
CheckedReturnTypes)))))))))
.bind("match"));

auto CheckCastToVoid =
AllowCastToVoid ? castExpr(unless(hasCastKind(CK_ToVoid))) : castExpr();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ using namespace clang::ast_matchers::internal;

namespace clang::tidy::cppcoreguidelines {

namespace {
AST_MATCHER_P(LambdaExpr, hasCallOperator, Matcher<CXXMethodDecl>,
InnerMatcher) {
return InnerMatcher.matches(*Node.getCallOperator(), Finder, Builder);
}

AST_MATCHER_P(LambdaExpr, hasLambdaBody, Matcher<Stmt>, InnerMatcher) {
return InnerMatcher.matches(*Node.getBody(), Finder, Builder);
}
} // namespace

void OwningMemoryCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "LegacyResourceProducers", LegacyResourceProducers);
Options.store(Opts, "LegacyResourceConsumers", LegacyResourceConsumers);
Expand Down Expand Up @@ -55,6 +66,8 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
CreatesLegacyOwner, LegacyOwnerCast);

const auto ConsideredOwner = eachOf(IsOwnerType, CreatesOwner);
const auto ScopeDeclaration = anyOf(translationUnitDecl(), namespaceDecl(),
recordDecl(), functionDecl());

// Find delete expressions that delete non-owners.
Finder->addMatcher(
Expand Down Expand Up @@ -144,13 +157,51 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) {
.bind("bad_owner_creation_parameter"))),
this);

auto IsNotInSubLambda = stmt(
hasAncestor(
stmt(anyOf(equalsBoundNode("body"), lambdaExpr())).bind("scope")),
hasAncestor(stmt(equalsBoundNode("scope"), equalsBoundNode("body"))));

// Matching on functions, that return an owner/resource, but don't declare
// their return type as owner.
Finder->addMatcher(
functionDecl(hasDescendant(returnStmt(hasReturnValue(ConsideredOwner))
.bind("bad_owner_return")),
unless(returns(qualType(hasDeclaration(OwnerDecl)))))
.bind("function_decl"),
functionDecl(
decl().bind("function_decl"),
hasBody(
stmt(stmt().bind("body"),
hasDescendant(
returnStmt(hasReturnValue(ConsideredOwner),
// Ignore sub-lambda expressions
IsNotInSubLambda,
// Ignore sub-functions
hasAncestor(functionDecl().bind("context")),
hasAncestor(functionDecl(
equalsBoundNode("context"),
equalsBoundNode("function_decl"))))
.bind("bad_owner_return")))),
returns(qualType(unless(hasDeclaration(OwnerDecl))).bind("result"))),
this);

// Matching on lambdas, that return an owner/resource, but don't declare
// their return type as owner.
Finder->addMatcher(
lambdaExpr(
hasAncestor(decl(ScopeDeclaration).bind("scope-decl")),
hasLambdaBody(
stmt(stmt().bind("body"),
hasDescendant(
returnStmt(
hasReturnValue(ConsideredOwner),
// Ignore sub-lambdas
IsNotInSubLambda,
// Ignore sub-functions
hasAncestor(decl(ScopeDeclaration).bind("context")),
hasAncestor(decl(equalsBoundNode("context"),
equalsBoundNode("scope-decl"))))
.bind("bad_owner_return")))),
hasCallOperator(returns(
qualType(unless(hasDeclaration(OwnerDecl))).bind("result"))))
.bind("lambda"),
this);

// Match on classes that have an owner as member, but don't declare a
Expand Down Expand Up @@ -329,7 +380,7 @@ bool OwningMemoryCheck::handleReturnValues(const BoundNodes &Nodes) {
// Function return statements, that are owners/resources, but the function
// declaration does not declare its return value as owner.
const auto *BadReturnType = Nodes.getNodeAs<ReturnStmt>("bad_owner_return");
const auto *Function = Nodes.getNodeAs<FunctionDecl>("function_decl");
const auto *ResultType = Nodes.getNodeAs<QualType>("result");

// Function return values, that should be owners but aren't.
if (BadReturnType) {
Expand All @@ -338,8 +389,9 @@ bool OwningMemoryCheck::handleReturnValues(const BoundNodes &Nodes) {
diag(BadReturnType->getBeginLoc(),
"returning a newly created resource of "
"type %0 or 'gsl::owner<>' from a "
"function whose return type is not 'gsl::owner<>'")
<< Function->getReturnType() << BadReturnType->getSourceRange();
"%select{function|lambda}1 whose return type is not 'gsl::owner<>'")
<< *ResultType << (Nodes.getNodeAs<Expr>("lambda") != nullptr)
<< BadReturnType->getSourceRange();

// FIXME: Rewrite the return type as 'gsl::owner<OriginalType>'
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ void fixGenericExprCastToBool(DiagnosticBuilder &Diag,

const Expr *SubExpr = Cast->getSubExpr();

bool NeedInnerParens =
SubExpr != nullptr && utils::fixit::areParensNeededForStatement(*SubExpr);
bool NeedInnerParens = utils::fixit::areParensNeededForStatement(*SubExpr);
bool NeedOuterParens =
Parent != nullptr && utils::fixit::areParensNeededForStatement(*Parent);

Expand Down
3 changes: 2 additions & 1 deletion clang-tools-extra/clangd/CodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,8 @@ struct CodeCompletionBuilder {
}
// 'CompletionItemKind::Interface' matches template type aliases.
if (Completion.Kind == CompletionItemKind::Interface ||
Completion.Kind == CompletionItemKind::Class) {
Completion.Kind == CompletionItemKind::Class ||
Completion.Kind == CompletionItemKind::Variable) {
if (Snippet->front() != '<')
return *Snippet; // Not an arg snippet?

Expand Down
5 changes: 4 additions & 1 deletion clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2648,12 +2648,15 @@ TEST(CompletionTest, CompletionFunctionArgsDisabled) {
class foo_class{};
template <class T>
using foo_alias = T**;
template <class T>
T foo_var = T{};
void f() { foo_^ })cpp",
{}, Opts);
EXPECT_THAT(
Results.Completions,
UnorderedElementsAre(AllOf(named("foo_class"), snippetSuffix("<$0>")),
AllOf(named("foo_alias"), snippetSuffix("<$0>"))));
AllOf(named("foo_alias"), snippetSuffix("<$0>")),
AllOf(named("foo_var"), snippetSuffix("<$0>"))));
}
{
auto Results = completions(
Expand Down
16 changes: 16 additions & 0 deletions clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ TEST_F(ExtractVariableTest, Test) {
)cpp";
EXPECT_UNAVAILABLE(NoCrashCasesC);

ExtraArgs = {"-xc"};
const char *NoCrashDesignator = R"cpp(
struct A {
struct {
int x;
};
};
struct B {
int y;
};
void foo(struct B *b) {
struct A a = {.x=b[[->]]y};
}
)cpp";
EXPECT_AVAILABLE(NoCrashDesignator);

ExtraArgs = {"-xobjective-c"};
const char *AvailableObjC = R"cpp(
__attribute__((objc_root_class))
Expand Down
11 changes: 11 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ New checks
Detects error-prone Curiously Recurring Template Pattern usage, when the CRTP
can be constructed outside itself and the derived class.

- New :doc:`bugprone-suspicious-stringview-data-usage
<clang-tidy/checks/bugprone/suspicious-stringview-data-usage>` check.

Identifies suspicious usages of ``std::string_view::data()`` that could lead
to reading out-of-bounds data due to inadequate or incorrect string null
termination.

- New :doc:`modernize-use-designated-initializers
<clang-tidy/checks/modernize/use-designated-initializers>` check.

Expand Down Expand Up @@ -165,6 +172,10 @@ Changes in existing checks
giving false positives for deleted functions and fix false negative when some
parameters are forwarded, but other aren't.

- Improved :doc:`cppcoreguidelines-owning-memory
<clang-tidy/checks/cppcoreguidelines/owning-memory>` check to properly handle
return type in lambdas and in nested functions.

- Cleaned up :doc:`cppcoreguidelines-prefer-member-initializer
<clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>`
by removing enforcement of rule `C.48
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.. title:: clang-tidy - bugprone-suspicious-stringview-data-usage

bugprone-suspicious-stringview-data-usage
=========================================

Identifies suspicious usages of ``std::string_view::data()`` that could lead to
reading out-of-bounds data due to inadequate or incorrect string null
termination.

It warns when the result of ``data()`` is passed to a constructor or function
without also passing the corresponding result of ``size()`` or ``length()``
member function. Such usage can lead to unintended behavior, particularly when
assuming the data pointed to by ``data()`` is null-terminated.

The absence of a ``c_str()`` method in ``std::string_view`` often leads
developers to use ``data()`` as a substitute, especially when interfacing with
C APIs that expect null-terminated strings. However, since ``data()`` does not
guarantee null termination, this can result in unintended behavior if the API
relies on proper null termination for correct string interpretation.

In today's programming landscape, this scenario can occur when implicitly
converting an ``std::string_view`` to an ``std::string``. Since the constructor
in ``std::string`` designed for string-view-like objects is ``explicit``,
attempting to pass an ``std::string_view`` to a function expecting an
``std::string`` will result in a compilation error. As a workaround, developers
may be tempted to utilize the ``.data()`` method to achieve compilation,
introducing potential risks.

For instance:

.. code-block:: c++

void printString(const std::string& str) {
std::cout << "String: " << str << std::endl;
}

void something(std::string_view sv) {
printString(sv.data());
}

In this example, directly passing ``sv`` to the ``printString`` function would
lead to a compilation error due to the explicit nature of the ``std::string``
constructor. Consequently, developers might opt for ``sv.data()`` to resolve the
compilation error, albeit introducing potential hazards as discussed.

.. option:: StringViewTypes

Option allows users to specify custom string view-like types for analysis. It
accepts a semicolon-separated list of type names or regular expressions
matching these types. Default value is:
`::std::basic_string_view;::llvm::StringRef`.

.. option:: AllowedCallees

Specifies methods, functions, or classes where the result of ``.data()`` is
passed to. Allows to exclude such calls from the analysis. Accepts a
semicolon-separated list of names or regular expressions matching these
entities. Default value is: empty string.
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ Clang-Tidy Checks
:doc:`bugprone-suspicious-realloc-usage <bugprone/suspicious-realloc-usage>`,
:doc:`bugprone-suspicious-semicolon <bugprone/suspicious-semicolon>`, "Yes"
:doc:`bugprone-suspicious-string-compare <bugprone/suspicious-string-compare>`, "Yes"
:doc:`bugprone-suspicious-stringview-data-usage <bugprone/suspicious-stringview-data-usage>`,
:doc:`bugprone-swapped-arguments <bugprone/swapped-arguments>`, "Yes"
:doc:`bugprone-switch-missing-default-case <bugprone/switch-missing-default-case>`,
:doc:`bugprone-terminating-continue <bugprone/terminating-continue>`, "Yes"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ struct basic_string {
basic_string();
basic_string(const C *p, const A &a = A());
basic_string(const C *p, size_type count);
basic_string(const C *b, const C *e);

~basic_string();

Expand Down Expand Up @@ -85,6 +86,12 @@ struct basic_string_view {
const C *str;
constexpr basic_string_view(const C* s) : str(s) {}

const C *data() const;

bool empty() const;
size_type size() const;
size_type length() const;

size_type find(_Type v, size_type pos = 0) const;
size_type find(C ch, size_type pos = 0) const;
size_type find(const C* s, size_type pos, size_type count) const;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-suspicious-stringview-data-usage %t -- -- -isystem %clang_tidy_headers
#include <string>

struct View {
const char* str;
};

struct Pair {
const char* begin;
const char* end;
};

struct ViewWithSize {
const char* str;
std::string_view::size_type size;
};

void something(const char*);
void something(const char*, unsigned);
void something(const char*, unsigned, const char*);
void something_str(std::string, unsigned);

void invalid(std::string_view sv, std::string_view sv2) {
std::string s(sv.data());
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: result of a `data()` call may not be null terminated, provide size information to the callee to prevent potential issues
std::string si{sv.data()};
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: result of a `data()` call may not be null terminated, provide size information to the callee to prevent potential issues
std::string_view s2(sv.data());
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: result of a `data()` call may not be null terminated, provide size information to the callee to prevent potential issues
something(sv.data());
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: result of a `data()` call may not be null terminated, provide size information to the callee to prevent potential issues
something(sv.data(), sv.size(), sv2.data());
// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: result of a `data()` call may not be null terminated, provide size information to the callee to prevent potential issues
something_str(sv.data(), sv.size());
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: result of a `data()` call may not be null terminated, provide size information to the callee to prevent potential issues
View view{sv.data()};
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: result of a `data()` call may not be null terminated, provide size information to the callee to prevent potential issues
}

void valid(std::string_view sv) {
std::string s1(sv.data(), sv.data() + sv.size());
std::string s2(sv.data(), sv.data() + sv.length());
std::string s3(sv.data(), sv.size() + sv.data());
std::string s4(sv.data(), sv.length() + sv.data());
std::string s5(sv.data(), sv.size());
std::string s6(sv.data(), sv.length());
something(sv.data(), sv.size());
something(sv.data(), sv.length());
ViewWithSize view1{sv.data(), sv.size()};
ViewWithSize view2{sv.data(), sv.length()};
Pair view3{sv.data(), sv.data() + sv.size()};
Pair view4{sv.data(), sv.data() + sv.length()};
Pair view5{sv.data(), sv.size() + sv.data()};
Pair view6{sv.data(), sv.length() + sv.data()};
const char* str{sv.data()};
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,53 @@
// RUN: {bugprone-unused-return-value.CheckedFunctions: "::*"}}' \
// RUN: --

struct S {
S(){};
S(S const &);
S(S &&);
S &operator=(S const &);
S &operator=(S &&);
S &operator+=(S);
struct S1 {
S1(){};
S1(S1 const &);
S1(S1 &&);
S1 &operator=(S1 const &);
S1 &operator=(S1 &&);
S1 &operator+=(S1);
S1 &operator++();
S1 &operator++(int);
S1 &operator--();
S1 &operator--(int);
};

S returnValue();
S const &returnRef();
struct S2 {
S2(){};
S2(S2 const &);
S2(S2 &&);
};

S2 &operator-=(S2&, int);
S2 &operator++(S2 &);
S2 &operator++(S2 &, int);

S1 returnValue();
S1 const &returnRef();

void bar() {
returnValue();
// CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should not be disregarded; neglecting it may lead to errors

S a{};
S1 a{};
a = returnValue();
a.operator=(returnValue());

a = returnRef();
a.operator=(returnRef());

a += returnRef();

a++;
++a;
a--;
--a;

S2 b{};

b -= 1;
b++;
++b;
}
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,109 @@ namespace PR63994 {
// CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'A *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
}
}

namespace PR59389 {
struct S {
S();
S(int);

int value = 1;
};

void testLambdaInFunctionNegative() {
const auto MakeS = []() -> ::gsl::owner<S*> {
return ::gsl::owner<S*>{new S{}};
};
}

void testLambdaInFunctionPositive() {
const auto MakeS = []() -> S* {
return ::gsl::owner<S*>{new S{}};
// CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
};
}

void testFunctionInFunctionNegative() {
struct C {
::gsl::owner<S*> test() {
return ::gsl::owner<S*>{new S{}};
}
};
}

void testFunctionInFunctionPositive() {
struct C {
S* test() {
return ::gsl::owner<S*>{new S{}};
// CHECK-NOTES: [[@LINE-1]]:9: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
}
};
}

::gsl::owner<S*> testReverseLambdaNegative() {
const auto MakeI = [] -> int { return 5; };
return ::gsl::owner<S*>{new S(MakeI())};
}

S* testReverseLambdaPositive() {
const auto MakeI = [] -> int { return 5; };
return ::gsl::owner<S*>{new S(MakeI())};
// CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
}

::gsl::owner<S*> testReverseFunctionNegative() {
struct C {
int test() { return 5; }
};
return ::gsl::owner<S*>{new S(C().test())};
}

S* testReverseFunctionPositive() {
struct C {
int test() { return 5; }
};
return ::gsl::owner<S*>{new S(C().test())};
// CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
}

void testLambdaInLambdaNegative() {
const auto MakeS = []() -> ::gsl::owner<S*> {
const auto MakeI = []() -> int { return 5; };
return ::gsl::owner<S*>{new S(MakeI())};
};
}

void testLambdaInLambdaPositive() {
const auto MakeS = []() -> S* {
const auto MakeI = []() -> int { return 5; };
return ::gsl::owner<S*>{new S(MakeI())};
// CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
};
}

void testLambdaInLambdaWithDoubleReturns() {
const auto MakeS = []() -> S* {
const auto MakeS2 = []() -> S* {
return ::gsl::owner<S*>{new S(1)};
// CHECK-NOTES: [[@LINE-1]]:9: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>' [cppcoreguidelines-owning-memory]
};
return ::gsl::owner<S*>{new S(2)};
// CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
};
}

void testReverseLambdaInLambdaNegative() {
const auto MakeI = []() -> int {
const auto MakeS = []() -> ::gsl::owner<S*> { return new S(); };
return 5;
};
}

void testReverseLambdaInLambdaPositive() {
const auto MakeI = []() -> int {
const auto MakeS = []() -> S* { return new S(); };
// CHECK-NOTES: [[@LINE-1]]:39: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
return 5;
};
}
}
5 changes: 3 additions & 2 deletions clang/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,11 +190,12 @@ set(CLANG_RESOURCE_DIR "" CACHE STRING
set(C_INCLUDE_DIRS "" CACHE STRING
"Colon separated list of directories clang will search for headers.")

set(USE_DEPRECATED_GCC_INSTALL_PREFIX OFF CACHE BOOL "Temporary workaround before GCC_INSTALL_PREFIX is completely removed")
set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." )
set(DEFAULT_SYSROOT "" CACHE STRING
"Default <path> to all compiler invocations for --sysroot=<path>." )
if(GCC_INSTALL_PREFIX)
message(WARNING "GCC_INSTALL_PREFIX is deprecated and will be removed. Use "
if(GCC_INSTALL_PREFIX AND NOT USE_DEPRECATED_GCC_INSTALL_PREFIX)
message(FATAL_ERROR "GCC_INSTALL_PREFIX is deprecated and will be removed. Use "
"configuration files (https://clang.llvm.org/docs/UsersManual.html#configuration-files)"
"to specify the default --gcc-install-dir= or --gcc-triple=. --gcc-toolchain= is discouraged. "
"See https://github.com/llvm/llvm-project/pull/77537 for detail.")
Expand Down
173 changes: 172 additions & 1 deletion clang/bindings/python/clang/cindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,29 @@ def __repr__(self):
# Represents an @available(...) check.
CursorKind.OBJC_AVAILABILITY_CHECK_EXPR = CursorKind(148)

# Fixed point literal.
CursorKind.FIXED_POINT_LITERAL = CursorKind(149)

# OpenMP 5.0 [2.1.4, Array Shaping].
CursorKind.OMP_ARRAY_SHAPING_EXPR = CursorKind(150)

# OpenMP 5.0 [2.1.6 Iterators].
CursorKind.OMP_ITERATOR_EXPR = CursorKind(151)

# OpenCL's addrspace_cast<> expression.
CursorKind.CXX_ADDRSPACE_CAST_EXPR = CursorKind(152)

# Expression that references a C++20 concept.
CursorKind.CONCEPT_SPECIALIZATION_EXPR = CursorKind(153)

# Expression that references a C++20 requires expression.
CursorKind.REQUIRES_EXPR = CursorKind(154)

# Expression that references a C++20 parenthesized list aggregate initializer.
CursorKind.CXX_PAREN_LIST_INIT_EXPR = CursorKind(155)

# Represents a C++26 pack indexing expression.
CursorKind.PACK_INDEXING_EXPR = CursorKind(156)

# A statement whose specific kind is not exposed via this interface.
#
Expand Down Expand Up @@ -1312,6 +1335,114 @@ def __repr__(self):
# OpenMP teams distribute directive.
CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(271)

# OpenMP teams distribute simd directive.
CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(272)

# OpenMP teams distribute parallel for simd directive.
CursorKind.OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE = CursorKind(273)

# OpenMP teams distribute parallel for directive.
CursorKind.OMP_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE = CursorKind(274)

# OpenMP target teams directive.
CursorKind.OMP_TARGET_TEAMS_DIRECTIVE = CursorKind(275)

# OpenMP target teams distribute directive.
CursorKind.OMP_TARGET_TEAMS_DISTRIBUTE_DIRECTIVE = CursorKind(276)

# OpenMP target teams distribute parallel for directive.
CursorKind.OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_DIRECTIVE = CursorKind(277)

# OpenMP target teams distribute parallel for simd directive.
CursorKind.OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE = CursorKind(278)

# OpenMP target teams distribute simd directive.
CursorKind.OMP_TARGET_TEAMS_DISTRIBUTE_SIMD_DIRECTIVE = CursorKind(279)

# C++2a std::bit_cast expression.
CursorKind.BUILTIN_BIT_CAST_EXPR = CursorKind(280)

# OpenMP master taskloop directive.
CursorKind.OMP_MASTER_TASK_LOOP_DIRECTIVE = CursorKind(281)

# OpenMP parallel master taskloop directive.
CursorKind.OMP_PARALLEL_MASTER_TASK_LOOP_DIRECTIVE = CursorKind(282)

# OpenMP master taskloop simd directive.
CursorKind.OMP_MASTER_TASK_LOOP_SIMD_DIRECTIVE = CursorKind(283)

# OpenMP parallel master taskloop simd directive.
CursorKind.OMP_PARALLEL_MASTER_TASK_LOOP_SIMD_DIRECTIVE = CursorKind(284)

# OpenMP parallel master directive.
CursorKind.OMP_PARALLEL_MASTER_DIRECTIVE = CursorKind(285)

# OpenMP depobj directive.
CursorKind.OMP_DEPOBJ_DIRECTIVE = CursorKind(286)

# OpenMP scan directive.
CursorKind.OMP_SCAN_DIRECTIVE = CursorKind(287)

# OpenMP tile directive.
CursorKind.OMP_TILE_DIRECTIVE = CursorKind(288)

# OpenMP canonical loop.
CursorKind.OMP_CANONICAL_LOOP = CursorKind(289)

# OpenMP interop directive.
CursorKind.OMP_INTEROP_DIRECTIVE = CursorKind(290)

# OpenMP dispatch directive.
CursorKind.OMP_DISPATCH_DIRECTIVE = CursorKind(291)

# OpenMP masked directive.
CursorKind.OMP_MASKED_DIRECTIVE = CursorKind(292)

# OpenMP unroll directive.
CursorKind.OMP_UNROLL_DIRECTIVE = CursorKind(293)

# OpenMP metadirective directive.
CursorKind.OMP_META_DIRECTIVE = CursorKind(294)

# OpenMP loop directive.
CursorKind.OMP_GENERIC_LOOP_DIRECTIVE = CursorKind(295)

# OpenMP teams loop directive.
CursorKind.OMP_TEAMS_GENERIC_LOOP_DIRECTIVE = CursorKind(296)

# OpenMP target teams loop directive.
CursorKind.OMP_TARGET_TEAMS_GENERIC_LOOP_DIRECTIVE = CursorKind(297)

# OpenMP parallel loop directive.
CursorKind.OMP_PARALLEL_GENERIC_LOOP_DIRECTIVE = CursorKind(298)

# OpenMP target parallel loop directive.
CursorKind.OMP_TARGET_PARALLEL_GENERIC_LOOP_DIRECTIVE = CursorKind(299)

# OpenMP parallel masked directive.
CursorKind.OMP_PARALLEL_MASKED_DIRECTIVE = CursorKind(300)

# OpenMP masked taskloop directive.
CursorKind.OMP_MASKED_TASK_LOOP_DIRECTIVE = CursorKind(301)

# OpenMP masked taskloop simd directive.
CursorKind.OMP_MASKED_TASK_LOOP_SIMD_DIRECTIVE = CursorKind(302)

# OpenMP parallel masked taskloop directive.
CursorKind.OMP_PARALLEL_MASKED_TASK_LOOP_DIRECTIVE = CursorKind(303)

# OpenMP parallel masked taskloop simd directive.
CursorKind.OMP_PARALLEL_MASKED_TASK_LOOP_SIMD_DIRECTIVE = CursorKind(304)

# OpenMP error directive.
CursorKind.OMP_ERROR_DIRECTIVE = CursorKind(305)

# OpenMP scope directive.
CursorKind.OMP_SCOPE_DIRECTIVE = CursorKind(306)

# OpenACC Compute Construct.
CursorKind.OPEN_ACC_COMPUTE_DIRECTIVE = CursorKind(320)

###
# Other Kinds

Expand Down Expand Up @@ -1349,6 +1480,24 @@ def __repr__(self):

CursorKind.DLLEXPORT_ATTR = CursorKind(418)
CursorKind.DLLIMPORT_ATTR = CursorKind(419)
CursorKind.NS_RETURNS_RETAINED = CursorKind(420)
CursorKind.NS_RETURNS_NOT_RETAINED = CursorKind(421)
CursorKind.NS_RETURNS_AUTORELEASED = CursorKind(422)
CursorKind.NS_CONSUMES_SELF = CursorKind(423)
CursorKind.NS_CONSUMED = CursorKind(424)
CursorKind.OBJC_EXCEPTION = CursorKind(425)
CursorKind.OBJC_NSOBJECT = CursorKind(426)
CursorKind.OBJC_INDEPENDENT_CLASS = CursorKind(427)
CursorKind.OBJC_PRECISE_LIFETIME = CursorKind(428)
CursorKind.OBJC_RETURNS_INNER_POINTER = CursorKind(429)
CursorKind.OBJC_REQUIRES_SUPER = CursorKind(430)
CursorKind.OBJC_ROOT_CLASS = CursorKind(431)
CursorKind.OBJC_SUBCLASSING_RESTRICTED = CursorKind(432)
CursorKind.OBJC_EXPLICIT_PROTOCOL_IMPL = CursorKind(433)
CursorKind.OBJC_DESIGNATED_INITIALIZER = CursorKind(434)
CursorKind.OBJC_RUNTIME_VISIBLE = CursorKind(435)
CursorKind.OBJC_BOXABLE = CursorKind(436)
CursorKind.FLAG_ENUM = CursorKind(437)
CursorKind.CONVERGENT_ATTR = CursorKind(438)
CursorKind.WARN_UNUSED_ATTR = CursorKind(439)
CursorKind.WARN_UNUSED_RESULT_ATTR = CursorKind(440)
Expand Down Expand Up @@ -1395,6 +1544,11 @@ class TemplateArgumentKind(BaseEnumeration):
TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2)
TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3)
TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4)
TemplateArgumentKind.TEMPLATE = TemplateArgumentKind(5)
TemplateArgumentKind.TEMPLATE_EXPANSION = TemplateArgumentKind(6)
TemplateArgumentKind.EXPRESSION = TemplateArgumentKind(7)
TemplateArgumentKind.PACK = TemplateArgumentKind(8)
TemplateArgumentKind.INVALID = TemplateArgumentKind(9)

### Exception Specification Kinds ###
class ExceptionSpecificationKind(BaseEnumeration):
Expand Down Expand Up @@ -2240,9 +2394,26 @@ def __repr__(self):
TypeKind.OCLQUEUE = TypeKind(159)
TypeKind.OCLRESERVEID = TypeKind(160)

TypeKind.OBJCOBJECT = TypeKind(161)
TypeKind.OBJCCLASS = TypeKind(162)
TypeKind.ATTRIBUTED = TypeKind(163)

TypeKind.OCLINTELSUBGROUPAVCMCEPAYLOAD = TypeKind(164)
TypeKind.OCLINTELSUBGROUPAVCIMEPAYLOAD = TypeKind(165)
TypeKind.OCLINTELSUBGROUPAVCREFPAYLOAD = TypeKind(166)
TypeKind.OCLINTELSUBGROUPAVCSICPAYLOAD = TypeKind(167)
TypeKind.OCLINTELSUBGROUPAVCMCERESULT = TypeKind(168)
TypeKind.OCLINTELSUBGROUPAVCIMERESULT = TypeKind(169)
TypeKind.OCLINTELSUBGROUPAVCREFRESULT = TypeKind(170)
TypeKind.OCLINTELSUBGROUPAVCSICRESULT = TypeKind(171)
TypeKind.OCLINTELSUBGROUPAVCIMERESULTSINGLEREFERENCESTREAMOUT = TypeKind(172)
TypeKind.OCLINTELSUBGROUPAVCIMERESULTSDUALREFERENCESTREAMOUT = TypeKind(173)
TypeKind.OCLINTELSUBGROUPAVCIMERESULTSSINGLEREFERENCESTREAMIN = TypeKind(174)
TypeKind.OCLINTELSUBGROUPAVCIMEDUALREFERENCESTREAMIN = TypeKind(175)

TypeKind.EXTVECTOR = TypeKind(176)
TypeKind.ATOMIC = TypeKind(177)

TypeKind.BTFTAGATTRIBUTED = TypeKind(178)

class RefQualifierKind(BaseEnumeration):
"""Describes a specific ref-qualifier of a type."""
Expand Down
1 change: 1 addition & 0 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "

set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_DIA_SDK OFF CACHE BOOL "")
set(LLVM_ENABLE_FATLTO ON CACHE BOOL "")
set(LLVM_ENABLE_HTTPLIB ON CACHE BOOL "")
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "")
Expand Down
1 change: 1 addition & 0 deletions clang/docs/ClangFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code.
--dry-run - If set, do not actually make the formatting changes
--dump-config - Dump configuration options to stdout and exit.
Can be used with -style option.
--fail-on-incomplete-format - If set, fail with exit code 1 on incomplete format.
--fallback-style=<string> - The name of the predefined style used as a
fallback in case clang-format is invoked with
-style=file, but can not find the .clang-format
Expand Down
209 changes: 209 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,151 @@ the configuration (without a prefix: ``Auto``).
}


.. _AlignConsecutiveTableGenBreakingDAGArgColons:

**AlignConsecutiveTableGenBreakingDAGArgColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ <AlignConsecutiveTableGenBreakingDAGArgColons>`
Style of aligning consecutive TableGen DAGArg operator colons.
If enabled, align the colon inside DAGArg which have line break inside.
This works only when TableGenBreakInsideDAGArg is BreakElements or
BreakAll and the DAGArg is not excepted by
TableGenBreakingDAGArgOperators's effect.

.. code-block:: c++

let dagarg = (ins
a :$src1,
aa :$src2,
aaa:$src3
)

Nested configuration flags:

Alignment options.

They can also be read as a whole for compatibility. The choices are:
- None
- Consecutive
- AcrossEmptyLines
- AcrossComments
- AcrossEmptyLinesAndComments

For example, to align across empty lines and not across comments, either
of these work.

.. code-block:: c++

AlignConsecutiveTableGenBreakingDAGArgColons: AcrossEmptyLines

AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false

* ``bool Enabled`` Whether aligning is enabled.

.. code-block:: c++

#define SHORT_NAME 42
#define LONGER_NAME 0x007f
#define EVEN_LONGER_NAME (2)
#define foo(x) (x * x)
#define bar(y, z) (y + z)

int a = 1;
int somelongname = 2;
double c = 3;

int aaaa : 1;
int b : 12;
int ccc : 8;

int aaaa = 12;
float b = 23;
std::string ccc;

* ``bool AcrossEmptyLines`` Whether to align across empty lines.

.. code-block:: c++

true:
int a = 1;
int somelongname = 2;
double c = 3;

int d = 3;

false:
int a = 1;
int somelongname = 2;
double c = 3;

int d = 3;

* ``bool AcrossComments`` Whether to align across comments.

.. code-block:: c++

true:
int d = 3;
/* A comment. */
double e = 4;
false:
int d = 3;
/* A comment. */
double e = 4;
* ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments
like ``+=`` are aligned along with ``=``.

.. code-block:: c++

true:
a &= 2;
bbb = 2;

false:
a &= 2;
bbb = 2;

* ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are
aligned.

.. code-block:: c++

true:
unsigned i;
int &r;
int *p;
int (*f)();
false:
unsigned i;
int &r;
int *p;
int (*f)();
* ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment
operators are left-padded to the same length as long ones in order to
put all assignment operators to the right of the left hand side.

.. code-block:: c++

true:
a >>= 2;
bbb = 2;

a = 2;
bbb >>= 2;

false:
a >>= 2;
bbb = 2;

a = 2;
bbb >>= 2;


.. _AlignConsecutiveTableGenCondOperatorColons:

**AlignConsecutiveTableGenCondOperatorColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ <AlignConsecutiveTableGenCondOperatorColons>`
Expand Down Expand Up @@ -6158,6 +6303,70 @@ the configuration (without a prefix: ``Auto``).
**TabWidth** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ <TabWidth>`
The number of columns used for tab stops.

.. _TableGenBreakInsideDAGArg:

**TableGenBreakInsideDAGArg** (``DAGArgStyle``) :versionbadge:`clang-format 19` :ref:`¶ <TableGenBreakInsideDAGArg>`
The styles of the line break inside the DAGArg in TableGen.

Possible values:

* ``DAS_DontBreak`` (in configuration: ``DontBreak``)
Never break inside DAGArg.

.. code-block:: c++

let DAGArgIns = (ins i32:$src1, i32:$src2);

* ``DAS_BreakElements`` (in configuration: ``BreakElements``)
Break inside DAGArg after each list element but for the last.
This aligns to the first element.

.. code-block:: c++

let DAGArgIns = (ins i32:$src1,
i32:$src2);

* ``DAS_BreakAll`` (in configuration: ``BreakAll``)
Break inside DAGArg after the operator and the all elements.

.. code-block:: c++

let DAGArgIns = (ins
i32:$src1,
i32:$src2
);



.. _TableGenBreakingDAGArgOperators:

**TableGenBreakingDAGArgOperators** (``List of Strings``) :versionbadge:`clang-format 19` :ref:`¶ <TableGenBreakingDAGArgOperators>`
Works only when TableGenBreakInsideDAGArg is not DontBreak.
The string list needs to consist of identifiers in TableGen.
If any identifier is specified, this limits the line breaks by
TableGenBreakInsideDAGArg option only on DAGArg values beginning with
the specified identifiers.

For example the configuration,

.. code-block:: yaml
TableGenBreakInsideDAGArg: BreakAll
TableGenBreakingDAGArgOperators: ['ins', 'outs']
makes the line break only occurs inside DAGArgs beginning with the
specified identifiers 'ins' and 'outs'.


.. code-block:: c++

let DAGArgIns = (ins
i32:$src1,
i32:$src2
);
let DAGArgOtherID = (other i32:$other1, i32:$other2);
let DAGArgBang = (!cast<SomeType>("Some") i32:$src1, i32:$src2)

.. _TypeNames:

**TypeNames** (``List of Strings``) :versionbadge:`clang-format 17` :ref:`¶ <TypeNames>`
Expand Down
50 changes: 49 additions & 1 deletion clang/docs/HLSL/HLSLSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ performance win for HLSL.

If precompiled headers are used when compiling HLSL, the ``ExternalSemaSource``
will be a ``MultiplexExternalSemaSource`` which includes both the ``ASTReader``
and ``HLSLExternalSemaSource``. For Built-in declarations that are already
and -. For Built-in declarations that are already
completed in the serialized AST, the ``HLSLExternalSemaSource`` will reuse the
existing declarations and not introduce new declarations. If the built-in types
are not completed in the serialized AST, the ``HLSLExternalSemaSource`` will
Expand All @@ -114,6 +114,54 @@ not re-targetable, we want to share the Clang CodeGen implementation for HLSL
with other GPU graphics targets like SPIR-V and possibly other GPU and even CPU
targets.

hlsl.h
------

HLSL has a library of standalone functions. This is similar to OpenCL and CUDA,
and is analogous to C's standard library. The implementation approach for the
HLSL library functionality draws from patterns in use by OpenCL and other Clang
resource headers. All of the clang resource headers are part of the
``ClangHeaders`` component found in the source tree under
`clang/lib/Headers <https://github.com/llvm/llvm-project/tree/main/clang/lib/Headers>`_.

.. note::

HLSL's complex data types are not defined in HLSL's header because many of
the semantics of those data types cannot be expressed in HLSL due to missing
language features. Data types that can't be expressed in HLSL are defined in
code in the ``HLSLExternalSemaSource``.

Similar to OpenCL, the HLSL library functionality is implicitly declared in
translation units without needing to include a header to provide declarations.
In Clang this is handled by making ``hlsl.h`` an implicitly included header
distributed as part of the Clang resource directory.

Similar to OpenCL, HLSL's implicit header will explicitly declare all overloads,
and each overload will map to a corresponding ``__builtin*`` compiler intrinsic
that is handled in ClangCodeGen. CUDA uses a similar pattern although many CUDA
functions have full definitions in the included headers which in turn call
corresponding ``__builtin*`` compiler intrinsics. By not having bodies HLSL
avoids the need for the inliner to clean up and inline large numbers of small
library functions.

HLSL's implicit headers also define some of HLSL's typedefs. This is consistent
with how the AVX vector header is implemented.

Concerns have been expressed that this approach may result in slower compile
times than the approach DXC uses where library functions are treated more like
Clang ``__builtin*`` intrinsics. No real world use cases have been identified
where parsing is a significant compile-time overhead, but the HLSL implicit
headers can be compiled into a module for performance if needed.

Further, by treating these as functions rather than ``__builtin*`` compiler
intrinsics, the language behaviors are more consistent and aligned with user
expectation because normal overload resolution rules and implicit conversions
apply as expected.

It is a feature of this design that clangd-powered "go to declaration" for
library functions will jump to a valid header declaration and all overloads will
be user readable.

HLSL Language
=============

Expand Down
121 changes: 86 additions & 35 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Clang Language Extensions
BlockLanguageSpec
Block-ABI-Apple
AutomaticReferenceCounting
PointerAuthentication
MatrixTypes

Introduction
Expand Down Expand Up @@ -1458,40 +1459,45 @@ More information could be found `here <https://clang.llvm.org/docs/Modules.html>
Language Extensions Back-ported to Previous Standards
=====================================================

====================================== ================================ ============= =============
Feature Feature Test Macro Introduced In Backported To
====================================== ================================ ============= =============
variadic templates __cpp_variadic_templates C++11 C++03
Alias templates __cpp_alias_templates C++11 C++03
Non-static data member initializers __cpp_nsdmi C++11 C++03
Range-based ``for`` loop __cpp_range_based_for C++11 C++03
RValue references __cpp_rvalue_references C++11 C++03
Attributes __cpp_attributes C++11 C++03
variable templates __cpp_variable_templates C++14 C++03
Binary literals __cpp_binary_literals C++14 C++03
Relaxed constexpr __cpp_constexpr C++14 C++11
``if constexpr`` __cpp_if_constexpr C++17 C++11
fold expressions __cpp_fold_expressions C++17 C++03
Lambda capture of \*this by value __cpp_capture_star_this C++17 C++11
Attributes on enums __cpp_enumerator_attributes C++17 C++03
Guaranteed copy elision __cpp_guaranteed_copy_elision C++17 C++03
Hexadecimal floating literals __cpp_hex_float C++17 C++03
``inline`` variables __cpp_inline_variables C++17 C++03
Attributes on namespaces __cpp_namespace_attributes C++17 C++11
Structured bindings __cpp_structured_bindings C++17 C++03
template template arguments __cpp_template_template_args C++17 C++03
``static operator[]`` __cpp_multidimensional_subscript C++20 C++03
Designated initializers __cpp_designated_initializers C++20 C++03
Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03
``using enum`` __cpp_using_enum C++20 C++03
``if consteval`` __cpp_if_consteval C++23 C++20
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
-------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Array & element qualification (N2607) C23 C89
Attributes (N2335) C23 C89
====================================== ================================ ============= =============
============================================ ================================ ============= =============
Feature Feature Test Macro Introduced In Backported To
============================================ ================================ ============= =============
variadic templates __cpp_variadic_templates C++11 C++03
Alias templates __cpp_alias_templates C++11 C++03
Non-static data member initializers __cpp_nsdmi C++11 C++03
Range-based ``for`` loop __cpp_range_based_for C++11 C++03
RValue references __cpp_rvalue_references C++11 C++03
Attributes __cpp_attributes C++11 C++03
Lambdas __cpp_lambdas C++11 C++03
Generalized lambda captures __cpp_init_captures C++14 C++03
Generic lambda expressions __cpp_generic_lambdas C++14 C++03
variable templates __cpp_variable_templates C++14 C++03
Binary literals __cpp_binary_literals C++14 C++03
Relaxed constexpr __cpp_constexpr C++14 C++11
Pack expansion in generalized lambda-capture __cpp_init_captures C++17 C++03
``if constexpr`` __cpp_if_constexpr C++17 C++11
fold expressions __cpp_fold_expressions C++17 C++03
Lambda capture of \*this by value __cpp_capture_star_this C++17 C++03
Attributes on enums __cpp_enumerator_attributes C++17 C++03
Guaranteed copy elision __cpp_guaranteed_copy_elision C++17 C++03
Hexadecimal floating literals __cpp_hex_float C++17 C++03
``inline`` variables __cpp_inline_variables C++17 C++03
Attributes on namespaces __cpp_namespace_attributes C++17 C++11
Structured bindings __cpp_structured_bindings C++17 C++03
template template arguments __cpp_template_template_args C++17 C++03
Familiar template syntax for generic lambdas __cpp_generic_lambdas C++20 C++03
``static operator[]`` __cpp_multidimensional_subscript C++20 C++03
Designated initializers __cpp_designated_initializers C++20 C++03
Conditional ``explicit`` __cpp_conditional_explicit C++20 C++03
``using enum`` __cpp_using_enum C++20 C++03
``if consteval`` __cpp_if_consteval C++23 C++20
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
-------------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Array & element qualification (N2607) C23 C89
Attributes (N2335) C23 C89
============================================ ================================ ============= =============

Type Trait Primitives
=====================
Expand Down Expand Up @@ -3444,7 +3450,7 @@ Query for this feature with ``__has_builtin(__builtin_debugtrap)``.
Query for this feature with ``__has_builtin(__builtin_trap)``.
``__builtin_arm_trap``
------------------
----------------------
``__builtin_arm_trap`` is an AArch64 extension to ``__builtin_trap`` which also accepts a compile-time constant value, encoded directly into the trap instruction for later inspection.
Expand Down Expand Up @@ -3547,6 +3553,47 @@ argument can be of any unsigned integer type.
``__builtin_popcount{,l,ll}`` builtins, with support for other integer types,
such as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
``__builtin_clzg`` and ``__builtin_ctzg``
-----------------------------------------
``__builtin_clzg`` (respectively ``__builtin_ctzg``) returns the number of
leading (respectively trailing) 0 bits in the first argument. The first argument
can be of any unsigned integer type.
If the first argument is 0 and an optional second argument of ``int`` type is
provided, then the second argument is returned. If the first argument is 0, but
only one argument is provided, then the behavior is undefined.
**Syntax**:
.. code-block:: c++
int __builtin_clzg(type x[, int fallback])
int __builtin_ctzg(type x[, int fallback])
**Examples**:
.. code-block:: c++
unsigned int x = 1;
int x_lz = __builtin_clzg(x);
int x_tz = __builtin_ctzg(x);
unsigned long y = 2;
int y_lz = __builtin_clzg(y);
int y_tz = __builtin_ctzg(y);
unsigned _BitInt(128) z = 4;
int z_lz = __builtin_clzg(z);
int z_tz = __builtin_ctzg(z);
**Description**:
``__builtin_clzg`` (respectively ``__builtin_ctzg``) is meant to be a
type-generic alternative to the ``__builtin_clz{,l,ll}`` (respectively
``__builtin_ctz{,l,ll}``) builtins, with support for other integer types, such
as ``unsigned __int128`` and C23 ``unsigned _BitInt(N)``.
Multiprecision Arithmetic Builtins
----------------------------------
Expand Down Expand Up @@ -4318,6 +4365,10 @@ reordering of memory accesses and side effect instructions. Other instructions
like simple arithmetic may be reordered around the intrinsic. If you expect to
have no reordering at all, use inline assembly instead.
Pointer Authentication
^^^^^^^^^^^^^^^^^^^^^^
See :doc:`PointerAuthentication`.
X86/X86-64 Language Extensions
------------------------------
Expand Down
485 changes: 485 additions & 0 deletions clang/docs/PointerAuthentication.rst

Large diffs are not rendered by default.

98 changes: 84 additions & 14 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ These changes are ones which we think may surprise users when upgrading to
Clang |release| because of the opportunity they pose for disruption to existing
code bases.

- Setting the deprecated CMake variable ``GCC_INSTALL_PREFIX`` (which sets the
default ``--gcc-toolchain=``) now leads to a fatal error.

C/C++ Language Potentially Breaking Changes
-------------------------------------------

Expand All @@ -47,6 +50,12 @@ C++ Specific Potentially Breaking Changes

ABI Changes in This Version
---------------------------
- Fixed Microsoft name mangling of implicitly defined variables used for thread
safe static initialization of static local variables. This change resolves
incompatibilities with code compiled by MSVC but might introduce
incompatibilities with code compiled by earlier versions of Clang when an
inline member function that contains a static local variable with a dynamic
initializer is declared with ``__declspec(dllimport)``. (#GH83616).

AST Dumping Potentially Breaking Changes
----------------------------------------
Expand Down Expand Up @@ -171,6 +180,8 @@ Non-comprehensive list of changes in this release
the previous builtins, this new builtin is constexpr and may be used in
constant expressions.

- Lambda expressions are now accepted in C++03 mode as an extension.

New Compiler Flags
------------------

Expand All @@ -187,10 +198,33 @@ Modified Compiler Flags
``-Wreturn-type``, and moved some of the diagnostics previously controlled by
``-Wreturn-type`` under this new flag. Fixes #GH72116.

- Added ``-Wcast-function-type-mismatch`` under the ``-Wcast-function-type``
warning group. Moved the diagnostic previously controlled by
``-Wcast-function-type`` to the new warning group and added
``-Wcast-function-type-mismatch`` to ``-Wextra``. #GH76872

.. code-block:: c
int x(long);
typedef int (f2)(void*);
typedef int (f3)();
void func(void) {
// Diagnoses under -Wcast-function-type, -Wcast-function-type-mismatch,
// -Wcast-function-type-strict, -Wextra
f2 *b = (f2 *)x;
// Diagnoses under -Wcast-function-type, -Wcast-function-type-strict
f3 *c = (f3 *)x;
}
Removed Compiler Flags
-------------------------

- The ``-freroll-loops`` flag has been removed. It had no effect since Clang 13.
- ``-m[no-]unaligned-access`` is removed for RISC-V and LoongArch.
``-m[no-]strict-align``, also supported by GCC, should be used instead.
(`#85350 <https://github.com/llvm/llvm-project/pull/85350>`_.)

Attribute Changes in Clang
--------------------------
Expand All @@ -201,20 +235,12 @@ Attribute Changes in Clang
and each must be a positive integer when provided. The parameter ``x`` is required, while ``y`` and
``z`` are optional with default value of 1.

- The ``_Nullable`` and ``_Nonnull`` family of type attributes can now apply
to certain C++ class types, such as smart pointers:
``void useObject(std::unique_ptr<Object> _Nonnull obj);``.

This works for standard library types including ``unique_ptr``, ``shared_ptr``
and ``function``. See `the attribute reference
documentation <https://llvm.org/docs/AttributeReference.html#nullability-attributes>`_
for the full list.

- The ``_Nullable`` attribute can be applied to C++ class declarations:
``template <class T> class _Nullable MySmartPointer {};``.

This allows the ``_Nullable`` and ``_Nonnull` family of type attributes to
apply to this class.
- The ``swiftasynccc`` attribute is now considered to be a Clang extension
rather than a language standard feature. Please use
``__has_extension(swiftasynccc)`` to check the availability of this attribute
for the target platform instead of ``__has_feature(swiftasynccc)``. Also,
added a new extension query ``__has_extension(swiftcc)`` corresponding to the
``__attribute__((swiftcc))`` attribute.

Improvements to Clang's diagnostics
-----------------------------------
Expand Down Expand Up @@ -256,6 +282,13 @@ Improvements to Clang's diagnostics
such as attempting to call ``free`` on an unallocated object. Fixes
`#79443 <https://github.com/llvm/llvm-project/issues/79443>`_.

- Clang no longer warns when the ``bitand`` operator is used with boolean
operands, distinguishing it from potential typographical errors or unintended
bitwise operations. Fixes #GH77601.

- Clang now correctly diagnoses no arguments to a variadic macro parameter as a C23/C++20 extension.
Fixes #GH84495.

Improvements to Clang's time-trace
----------------------------------

Expand Down Expand Up @@ -286,6 +319,9 @@ Bug Fixes in This Version
for variables created through copy initialization having side-effects in C++17 and later.
Fixes (#GH64356) (#GH79518).

- Fix value of predefined macro ``__FUNCTION__`` in MSVC compatibility mode.
Fixes (#GH66114).

- Clang now emits errors for explicit specializations/instatiations of lambda call
operator.
Fixes (#GH83267).
Expand All @@ -300,6 +336,9 @@ Bug Fixes in This Version
by the C standard. This significantly improves codegen of `*` and `/` especially.
Fixes (`#31205 <https://github.com/llvm/llvm-project/issues/31205>`_).

- Fixes an assertion failure on invalid code when trying to define member
functions in lambdas.

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -393,6 +432,11 @@ Bug Fixes to C++ Support
Fixes (#GH80997)
- Fix an issue where missing set friend declaration in template class instantiation.
Fixes (#GH84368).
- Fixed a crash while checking constraints of a trailing requires-expression of a lambda, that the
expression references to an entity declared outside of the lambda. (#GH64808)
- Clang's __builtin_bit_cast will now produce a constant value for records with empty bases. See:
(#GH82383)
- Fix a crash when instantiating a lambda that captures ``this`` outside of its context. Fixes (#GH85343).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -440,20 +484,43 @@ Arm and AArch64 Support
like ``target_version`` or ``target_clones``.
- Support has been added for the following processors (-mcpu identifiers in parenthesis):
* Arm Cortex-A78AE (cortex-a78ae).
* Arm Cortex-A520AE (cortex-a520ae).
* Arm Cortex-A720AE (cortex-a720ae).

Android Support
^^^^^^^^^^^^^^^

Windows Support
^^^^^^^^^^^^^^^

- Clang-cl now supports function targets with intrinsic headers. This allows
for runtime feature detection of intrinsics. Previously under clang-cl
``immintrin.h`` and similar intrinsic headers would only include the intrinsics
if building with that feature enabled at compile time, e.g. ``avxintrin.h``
would only be included if AVX was enabled at compile time. This was done to work
around include times from MSVC STL including ``intrin.h`` under clang-cl.
Clang-cl now provides ``intrin0.h`` for MSVC STL and therefore all intrinsic
features without requiring enablement at compile time.
Fixes: (`#53520 <https://github.com/llvm/llvm-project/issues/53520>`_)

- Improved compile times with MSVC STL. MSVC provides ``intrin0.h`` which is a
header that only includes intrinsics that are used by MSVC STL to avoid the
use of ``intrin.h``. MSVC STL when compiled under clang uses ``intrin.h``
instead. Clang-cl now provides ``intrin0.h`` for the same compiler throughput
purposes as MSVC. Clang-cl also provides ``yvals_core.h`` to redefine
``_STL_INTRIN_HEADER`` to expand to ``intrin0.h`` instead of ``intrin.h``.
This also means that if all intrinsic features are enabled at compile time
including STL headers will no longer slow down compile times since ``intrin.h``
is not included from MSVC STL.

LoongArch Support
^^^^^^^^^^^^^^^^^

RISC-V Support
^^^^^^^^^^^^^^

- ``__attribute__((rvv_vector_bits(N)))`` is now supported for RVV vbool*_t types.
- Profile names in ``-march`` option are now supported.

CUDA/HIP Language Changes
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -510,6 +577,7 @@ Static Analyzer
- Fixed crashing on loops if the loop variable was declared in switch blocks
but not under any case blocks if ``unroll-loops=true`` analyzer config is
set. (#GH68819)
- Support C++23 static operator calls. (#GH84972)

New features
^^^^^^^^^^^^
Expand Down Expand Up @@ -545,6 +613,8 @@ Python Binding Changes
----------------------

- Exposed `CXRewriter` API as `class Rewriter`.
- Add some missing kinds from Index.h (CursorKind: 149-156, 272-320, 420-437.
TemplateArgumentKind: 5-9. TypeKind: 161-175 and 178).

OpenMP Support
--------------
Expand Down
45 changes: 38 additions & 7 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1847,19 +1847,50 @@ floating point semantic models: precise (the default), strict, and fast.
* ``16`` - Forces ``_Float16`` operations to be emitted without using excess
precision arithmetic.

.. option:: -fcomplex-arithmetic=<value>:

This option specifies the implementation for complex multiplication and division.

Valid values are: ``basic``, ``improved``, ``full`` and ``promoted``.

* ``basic`` Implementation of complex division and multiplication using
algebraic formulas at source precision. No special handling to avoid
overflow. NaN and infinite values are not handled.
* ``improved`` Implementation of complex division using the Smith algorithm
at source precision. Smith's algorithm for complex division.
See SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8 (1962).
This value offers improved handling for overflow in intermediate
calculations, but overflow may occur. NaN and infinite values are not
handled in some cases.
* ``full`` Implementation of complex division and multiplication using a
call to runtime library functions (generally the case, but the BE might
sometimes replace the library call if it knows enough about the potential
range of the inputs). Overflow and non-finite values are handled by the
library implementation. For the case of multiplication overflow will occur in
accordance with normal floating-point rules. This is the default value.
* ``promoted`` Implementation of complex division using algebraic formulas at
higher precision. Overflow is handled. Non-finite values are handled in some
cases. If the target does not have native support for a higher precision
data type, the implementation for the complex operation using the Smith
algorithm will be used. Overflow may still occur in some cases. NaN and
infinite values are not handled.

.. option:: -fcx-limited-range:

This option enables the naive mathematical formulas for complex division and
multiplication with no NaN checking of results. The default is
``-fno-cx-limited-range``, but this option is enabled by the ``-ffast-math``
This option is aliased to ``-fcomplex-arithmetic=basic``. It enables the
naive mathematical formulas for complex division and multiplication with no
NaN checking of results. The default is ``-fno-cx-limited-range`` aliased to
``-fcomplex-arithmetic=full``. This option is enabled by the ``-ffast-math``
option.

.. option:: -fcx-fortran-rules:

This option enables the naive mathematical formulas for complex
multiplication and enables application of Smith's algorithm for complex
division. See SMITH, R. L. Algorithm 116: Complex division. Commun.
ACM 5, 8 (1962). The default is ``-fno-cx-fortran-rules``.
This option is aliased to ``-fcomplex-arithmetic=improved``. It enables the
naive mathematical formulas for complex multiplication and enables application
of Smith's algorithm for complex division. See SMITH, R. L. Algorithm 116:
Complex division. Commun. ACM 5, 8 (1962).
The default is ``-fno-cx-fortran-rules`` aliased to
``-fcomplex-arithmetic=full``.

.. _floating-point-environment:

Expand Down
3 changes: 2 additions & 1 deletion clang/docs/tools/clang-formatted-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ clang/include/clang/Analysis/MacroExpansionContext.h
clang/include/clang/Analysis/Analyses/CalledOnceCheck.h
clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h
clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
Expand Down Expand Up @@ -306,7 +307,7 @@ clang/include/clang-c/Index.h
clang/lib/Analysis/CalledOnceCheck.cpp
clang/lib/Analysis/CloneDetection.cpp
clang/lib/Analysis/CodeInjector.cpp
clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp
clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -1675,7 +1675,7 @@ enum CXCursorKind {
CXCursor_ConceptSpecializationExpr = 153,

/**
* Expression that references a C++20 concept.
* Expression that references a C++20 requires expression.
*/
CXCursor_RequiresExpr = 154,

Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
DependentBitIntTypes;
llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;

mutable llvm::FoldingSet<CountAttributedType> CountAttributedTypes;

mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
Expand Down Expand Up @@ -1341,6 +1343,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
}

QualType
getCountAttributedType(QualType T, Expr *CountExpr, bool CountInBytes,
bool OrNull,
ArrayRef<TypeCoupledDeclRefInfo> DependentDecls) const;

/// Return the uniqued reference to a type adjusted from the original
/// type to a new type.
QualType getAdjustedType(QualType Orig, QualType New) const;
Expand Down
19 changes: 15 additions & 4 deletions clang/include/clang/AST/Availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ struct AvailabilityInfo {
VersionTuple Introduced;
VersionTuple Deprecated;
VersionTuple Obsoleted;
bool Unavailable = false;
bool UnconditionallyDeprecated = false;
bool UnconditionallyUnavailable = false;

Expand All @@ -75,6 +76,15 @@ struct AvailabilityInfo {
/// Determine if this AvailabilityInfo represents the default availability.
bool isDefault() const { return *this == AvailabilityInfo(); }

/// Check if the symbol has been obsoleted.
bool isObsoleted() const { return !Obsoleted.empty(); }

/// Check if the symbol is unavailable unconditionally or
/// on the active platform and os version.
bool isUnavailable() const {
return Unavailable || isUnconditionallyUnavailable();
}

/// Check if the symbol is unconditionally deprecated.
///
/// i.e. \code __attribute__((deprecated)) \endcode
Expand All @@ -88,9 +98,10 @@ struct AvailabilityInfo {
}

AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D,
VersionTuple O, bool UD, bool UU)
VersionTuple O, bool U, bool UD, bool UU)
: Domain(Domain), Introduced(I), Deprecated(D), Obsoleted(O),
UnconditionallyDeprecated(UD), UnconditionallyUnavailable(UU) {}
Unavailable(U), UnconditionallyDeprecated(UD),
UnconditionallyUnavailable(UU) {}

friend bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs);
Expand All @@ -102,10 +113,10 @@ struct AvailabilityInfo {
inline bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs) {
return std::tie(Lhs.Introduced, Lhs.Deprecated, Lhs.Obsoleted,
Lhs.UnconditionallyDeprecated,
Lhs.Unavailable, Lhs.UnconditionallyDeprecated,
Lhs.UnconditionallyUnavailable) ==
std::tie(Rhs.Introduced, Rhs.Deprecated, Rhs.Obsoleted,
Rhs.UnconditionallyDeprecated,
Rhs.Unavailable, Rhs.UnconditionallyDeprecated,
Rhs.UnconditionallyUnavailable);
}

Expand Down
15 changes: 14 additions & 1 deletion clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2045,7 +2045,8 @@ class PredefinedExpr final
}

static std::string ComputeName(PredefinedIdentKind IK,
const Decl *CurrentDecl);
const Decl *CurrentDecl,
bool ForceElaboratedPrinting = false);

SourceLocation getBeginLoc() const { return getLocation(); }
SourceLocation getEndLoc() const { return getLocation(); }
Expand Down Expand Up @@ -3561,6 +3562,18 @@ class CastExpr : public Expr {
path_const_iterator path_begin() const { return path_buffer(); }
path_const_iterator path_end() const { return path_buffer() + path_size(); }

/// Path through the class hierarchy taken by casts between base and derived
/// classes (see implementation of `CastConsistency()` for a full list of
/// cast kinds that have a path).
///
/// For each derived-to-base edge in the path, the path contains a
/// `CXXBaseSpecifier` for the base class of that edge; the entries are
/// ordered from derived class to base class.
///
/// For example, given classes `Base`, `Intermediate : public Base` and
/// `Derived : public Intermediate`, the path for a cast from `Derived *` to
/// `Base *` contains two entries: One for `Intermediate`, and one for `Base`,
/// in that order.
llvm::iterator_range<path_iterator> path() {
return llvm::make_range(path_begin(), path_end());
}
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def UInt32 : CountPropertyType<"uint32_t">;
def UInt64 : CountPropertyType<"uint64_t">;
def UnaryTypeTransformKind : EnumPropertyType<"UnaryTransformType::UTTKind">;
def VectorKind : EnumPropertyType<"VectorKind">;
def TypeCoupledDeclRefInfo : PropertyType;

def ExceptionSpecInfo : PropertyType<"FunctionProtoType::ExceptionSpecInfo"> {
let BufferElementTypes = [ QualType ];
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,12 @@ DEF_TRAVERSE_TYPE(InjectedClassNameType, {})
DEF_TRAVERSE_TYPE(AttributedType,
{ TRY_TO(TraverseType(T->getModifiedType())); })

DEF_TRAVERSE_TYPE(CountAttributedType, {
if (T->getCountExpr())
TRY_TO(TraverseStmt(T->getCountExpr()));
TRY_TO(TraverseType(T->desugar()));
})

DEF_TRAVERSE_TYPE(BTFTagAttributedType,
{ TRY_TO(TraverseType(T->getWrappedType())); })

Expand Down Expand Up @@ -1401,6 +1407,9 @@ DEF_TRAVERSE_TYPELOC(MacroQualifiedType,
DEF_TRAVERSE_TYPELOC(AttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); })

DEF_TRAVERSE_TYPELOC(CountAttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })

DEF_TRAVERSE_TYPELOC(BTFTagAttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })

Expand Down
161 changes: 161 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class BTFTypeTagAttr;
class ExtQuals;
class QualType;
class ConceptDecl;
class ValueDecl;
class TagDecl;
class TemplateParameterList;
class Type;
Expand Down Expand Up @@ -2000,6 +2001,21 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
unsigned NumExpansions;
};

class CountAttributedTypeBitfields {
friend class CountAttributedType;

LLVM_PREFERRED_TYPE(TypeBitfields)
unsigned : NumTypeBits;

static constexpr unsigned NumCoupledDeclsBits = 4;
unsigned NumCoupledDecls : NumCoupledDeclsBits;
LLVM_PREFERRED_TYPE(bool)
unsigned CountInBytes : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned OrNull : 1;
};
static_assert(sizeof(CountAttributedTypeBitfields) <= sizeof(unsigned));

union {
TypeBitfields TypeBits;
ArrayTypeBitfields ArrayTypeBits;
Expand All @@ -2022,6 +2038,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
DependentTemplateSpecializationTypeBitfields
DependentTemplateSpecializationTypeBits;
PackExpansionTypeBitfields PackExpansionTypeBits;
CountAttributedTypeBitfields CountAttributedTypeBits;
};

private:
Expand Down Expand Up @@ -2245,6 +2262,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half)
bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661
bool isFloat32Type() const;
bool isDoubleType() const;
bool isBFloat16Type() const;
bool isFloat128Type() const;
bool isIbm128Type() const;
Expand All @@ -2263,6 +2281,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); }
bool isPointerType() const;
bool isAnyPointerType() const; // Any C pointer or ObjC object pointer
bool isCountAttributedType() const;
bool isBlockPointerType() const;
bool isVoidPointerType() const;
bool isReferenceType() const;
Expand Down Expand Up @@ -2723,6 +2742,14 @@ template <> const TemplateSpecializationType *Type::getAs() const;
/// until it reaches an AttributedType or a non-sugared type.
template <> const AttributedType *Type::getAs() const;

/// This will check for a BoundsAttributedType by removing any existing
/// sugar until it reaches an BoundsAttributedType or a non-sugared type.
template <> const BoundsAttributedType *Type::getAs() const;

/// This will check for a CountAttributedType by removing any existing
/// sugar until it reaches an CountAttributedType or a non-sugared type.
template <> const CountAttributedType *Type::getAs() const;

// We can do canonical leaf types faster, because we don't have to
// worry about preserving child type decoration.
#define TYPE(Class, Base)
Expand Down Expand Up @@ -2921,6 +2948,136 @@ class PointerType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) { return T->getTypeClass() == Pointer; }
};

/// [BoundsSafety] Represents information of declarations referenced by the
/// arguments of the `counted_by` attribute and the likes.
class TypeCoupledDeclRefInfo {
public:
using BaseTy = llvm::PointerIntPair<ValueDecl *, 1, unsigned>;

private:
enum {
DerefShift = 0,
DerefMask = 1,
};
BaseTy Data;

public:
/// \p D is to a declaration referenced by the argument of attribute. \p Deref
/// indicates whether \p D is referenced as a dereferenced form, e.g., \p
/// Deref is true for `*n` in `int *__counted_by(*n)`.
TypeCoupledDeclRefInfo(ValueDecl *D = nullptr, bool Deref = false);

bool isDeref() const;
ValueDecl *getDecl() const;
unsigned getInt() const;
void *getOpaqueValue() const;
bool operator==(const TypeCoupledDeclRefInfo &Other) const;
void setFromOpaqueValue(void *V);
};

/// [BoundsSafety] Represents a parent type class for CountAttributedType and
/// similar sugar types that will be introduced to represent a type with a
/// bounds attribute.
///
/// Provides a common interface to navigate declarations referred to by the
/// bounds expression.

class BoundsAttributedType : public Type, public llvm::FoldingSetNode {
QualType WrappedTy;

protected:
ArrayRef<TypeCoupledDeclRefInfo> Decls; // stored in trailing objects

BoundsAttributedType(TypeClass TC, QualType Wrapped, QualType Canon);

public:
bool isSugared() const { return true; }
QualType desugar() const { return WrappedTy; }

using decl_iterator = const TypeCoupledDeclRefInfo *;
using decl_range = llvm::iterator_range<decl_iterator>;

decl_iterator dependent_decl_begin() const { return Decls.begin(); }
decl_iterator dependent_decl_end() const { return Decls.end(); }

unsigned getNumCoupledDecls() const { return Decls.size(); }

decl_range dependent_decls() const {
return decl_range(dependent_decl_begin(), dependent_decl_end());
}

ArrayRef<TypeCoupledDeclRefInfo> getCoupledDecls() const {
return {dependent_decl_begin(), dependent_decl_end()};
}

bool referencesFieldDecls() const;

static bool classof(const Type *T) {
// Currently, only `class CountAttributedType` inherits
// `BoundsAttributedType` but the subclass will grow as we add more bounds
// annotations.
switch (T->getTypeClass()) {
case CountAttributed:
return true;
default:
return false;
}
}
};

/// Represents a sugar type with `__counted_by` or `__sized_by` annotations,
/// including their `_or_null` variants.
class CountAttributedType final
: public BoundsAttributedType,
public llvm::TrailingObjects<CountAttributedType,
TypeCoupledDeclRefInfo> {
friend class ASTContext;

Expr *CountExpr;
/// \p CountExpr represents the argument of __counted_by or the likes. \p
/// CountInBytes indicates that \p CountExpr is a byte count (i.e.,
/// __sized_by(_or_null)) \p OrNull means it's an or_null variant (i.e.,
/// __counted_by_or_null or __sized_by_or_null) \p CoupledDecls contains the
/// list of declarations referenced by \p CountExpr, which the type depends on
/// for the bounds information.
CountAttributedType(QualType Wrapped, QualType Canon, Expr *CountExpr,
bool CountInBytes, bool OrNull,
ArrayRef<TypeCoupledDeclRefInfo> CoupledDecls);

unsigned numTrailingObjects(OverloadToken<TypeCoupledDeclRefInfo>) const {
return CountAttributedTypeBits.NumCoupledDecls;
}

public:
enum DynamicCountPointerKind {
CountedBy = 0,
SizedBy,
CountedByOrNull,
SizedByOrNull,
};

Expr *getCountExpr() const { return CountExpr; }
bool isCountInBytes() const { return CountAttributedTypeBits.CountInBytes; }
bool isOrNull() const { return CountAttributedTypeBits.OrNull; }

DynamicCountPointerKind getKind() const {
if (isOrNull())
return isCountInBytes() ? SizedByOrNull : CountedByOrNull;
return isCountInBytes() ? SizedBy : CountedBy;
}

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, desugar(), CountExpr, isCountInBytes(), isOrNull());
}

static void Profile(llvm::FoldingSetNodeID &ID, QualType WrappedTy,
Expr *CountExpr, bool CountInBytes, bool Nullable);

static bool classof(const Type *T) {
return T->getTypeClass() == CountAttributed;
}
};

/// Represents a type which was implicitly adjusted by the semantic
/// engine for arbitrary reasons. For example, array and function types can
/// decay, and function types can have their calling conventions adjusted.
Expand Down Expand Up @@ -7457,6 +7614,10 @@ inline bool Type::isFloat32Type() const {
return isSpecificBuiltinType(BuiltinType::Float);
}

inline bool Type::isDoubleType() const {
return isSpecificBuiltinType(BuiltinType::Double);
}

inline bool Type::isBFloat16Type() const {
return isSpecificBuiltinType(BuiltinType::BFloat16);
}
Expand Down
26 changes: 26 additions & 0 deletions clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,32 @@ class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<ObjCObjectTypeLoc,
}
};

struct BoundsAttributedLocInfo {};
class BoundsAttributedTypeLoc
: public ConcreteTypeLoc<UnqualTypeLoc, BoundsAttributedTypeLoc,
BoundsAttributedType, BoundsAttributedLocInfo> {
public:
TypeLoc getInnerLoc() const { return getInnerTypeLoc(); }
QualType getInnerType() const { return getTypePtr()->desugar(); }
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
// nothing to do
}
// LocalData is empty and TypeLocBuilder doesn't handle DataSize 1.
unsigned getLocalDataSize() const { return 0; }
};

class CountAttributedTypeLoc final
: public InheritingConcreteTypeLoc<BoundsAttributedTypeLoc,
CountAttributedTypeLoc,
CountAttributedType> {
public:
Expr *getCountExpr() const { return getTypePtr()->getCountExpr(); }
bool isCountInBytes() const { return getTypePtr()->isCountInBytes(); }
bool isOrNull() const { return getTypePtr()->isOrNull(); }

SourceRange getLocalSourceRange() const;
};

struct MacroQualifiedLocInfo {
SourceLocation ExpansionLoc;
};
Expand Down
19 changes: 19 additions & 0 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ let Class = PointerType in {
def : Creator<[{ return ctx.getPointerType(pointeeType); }]>;
}

let Class = CountAttributedType in {
def : Property<"WrappedTy", QualType> {
let Read = [{ node->desugar() }];
}
def : Property<"CountExpr", ExprRef> {
let Read = [{ node->getCountExpr() }];
}
def : Property<"CountInBytes", Bool> {
let Read = [{ node->isCountInBytes() }];
}
def : Property<"OrNull", Bool> {
let Read = [{ node->isOrNull() }];
}
def : Property<"CoupledDecls", Array<TypeCoupledDeclRefInfo>> {
let Read = [{ node->getCoupledDecls() }];
}
def : Creator<[{ return ctx.getCountAttributedType(WrappedTy, CountExpr, CountInBytes, OrNull, CoupledDecls); }]>;
}

let Class = AdjustedType in {
def : Property<"originalType", QualType> {
let Read = [{ node->getOriginalType() }];
Expand Down
96 changes: 96 additions & 0 deletions clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//===-- AdornedCFG.h ------------------------------------*- 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 an AdornedCFG class that is used by dataflow analyses that
// run over Control-Flow Graphs (CFGs).
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "clang/Analysis/CFG.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Error.h"
#include <memory>
#include <utility>

namespace clang {
namespace dataflow {

/// Holds CFG with additional information derived from it that is needed to
/// perform dataflow analysis.
class AdornedCFG {
public:
/// Builds an `AdornedCFG` from a `FunctionDecl`.
/// `Func.doesThisDeclarationHaveABody()` must be true, and
/// `Func.isTemplated()` must be false.
static llvm::Expected<AdornedCFG> build(const FunctionDecl &Func);

/// Builds an `AdornedCFG` from an AST node. `D` is the function in which
/// `S` resides. `D.isTemplated()` must be false.
static llvm::Expected<AdornedCFG> build(const Decl &D, Stmt &S,
ASTContext &C);

/// Returns the `Decl` containing the statement used to construct the CFG, if
/// available.
const Decl &getDecl() const { return ContainingDecl; }

/// Returns the CFG that is stored in this context.
const CFG &getCFG() const { return *Cfg; }

/// Returns a mapping from statements to basic blocks that contain them.
const llvm::DenseMap<const Stmt *, const CFGBlock *> &getStmtToBlock() const {
return StmtToBlock;
}

/// Returns whether `B` is reachable from the entry block.
bool isBlockReachable(const CFGBlock &B) const {
return BlockReachable[B.getBlockID()];
}

/// Returns whether `B` contains an expression that is consumed in a
/// different block than `B` (i.e. the parent of the expression is in a
/// different block).
/// This happens if there is control flow within a full-expression (triggered
/// by `&&`, `||`, or the conditional operator). Note that the operands of
/// these operators are not the only expressions that can be consumed in a
/// different block. For example, in the function call
/// `f(&i, cond() ? 1 : 0)`, `&i` is in a different block than the `CallExpr`.
bool containsExprConsumedInDifferentBlock(const CFGBlock &B) const {
return ContainsExprConsumedInDifferentBlock.contains(&B);
}

private:
AdornedCFG(
const Decl &D, std::unique_ptr<CFG> Cfg,
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock,
llvm::BitVector BlockReachable,
llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock)
: ContainingDecl(D), Cfg(std::move(Cfg)),
StmtToBlock(std::move(StmtToBlock)),
BlockReachable(std::move(BlockReachable)),
ContainsExprConsumedInDifferentBlock(
std::move(ContainsExprConsumedInDifferentBlock)) {}

/// The `Decl` containing the statement used to construct the CFG.
const Decl &ContainingDecl;
std::unique_ptr<CFG> Cfg;
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock;
llvm::BitVector BlockReachable;
llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock;
};

} // namespace dataflow
} // namespace clang

#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H
Loading