226 changes: 113 additions & 113 deletions clang-tools-extra/clangd/test/protocol.test
Original file line number Diff line number Diff line change
@@ -1,113 +1,113 @@
# RUN: not clangd -pretty -sync -enable-test-uri-scheme < %s | FileCheck -strict-whitespace %s
# RUN: not clangd -pretty -sync -enable-test-uri-scheme < %s 2>&1 | FileCheck -check-prefix=STDERR %s
# vim: fileformat=dos
# It is absolutely vital that this file has CRLF line endings.
#
# Note that we invert the test because we intent to let clangd exit prematurely.
#
# Test protocol parsing
Content-Length: 125
Content-Type: application/vscode-jsonrpc; charset-utf-8

{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
# Test message with Content-Type after Content-Length
#
# CHECK: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK: }
Content-Length: 246

{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct fake { int a, bb, ccc; int f(int i, const float f) const; };\nint main() {\n fake f;\n f.\n}\n"}}}

Content-Length: 104

{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp"}}}

Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 146

{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with Content-Type before Content-Length
#
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "isIncomplete": false,
# CHECK-NEXT: "items": [
# CHECK: "filterText": "a",
# CHECK-NEXT: "insertText": "a",
# CHECK-NEXT: "insertTextFormat": 1,
# CHECK-NEXT: "kind": 5,
# CHECK-NEXT: "label": " a",
# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
# CHECK-NEXT: "sortText": "{{.*}}"
# CHECK: ]
# CHECK-NEXT: }

X-Test: Testing
Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 146
Content-Type: application/vscode-jsonrpc; charset-utf-8
X-Testing: Test

{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}

Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 10
Content-Length: 146

{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with duplicate Content-Length headers
#
# CHECK: "id": 3,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "isIncomplete": false,
# CHECK-NEXT: "items": [
# CHECK: "filterText": "a",
# CHECK-NEXT: "insertText": "a",
# CHECK-NEXT: "insertTextFormat": 1,
# CHECK-NEXT: "kind": 5,
# CHECK-NEXT: "label": " a",
# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
# CHECK-NEXT: "sortText": "{{.*}}"
# CHECK: ]
# CHECK-NEXT: }
# STDERR: Warning: Duplicate Content-Length header received. The previous value for this message (10) was ignored.

Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 10

{"jsonrpc":"2.0","id":4,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with malformed Content-Length
#
# STDERR: JSON parse error
# Ensure we recover by sending another (valid) message

Content-Length: 146

{"jsonrpc":"2.0","id":5,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with Content-Type before Content-Length
#
# CHECK: "id": 5,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "isIncomplete": false,
# CHECK-NEXT: "items": [
# CHECK: "filterText": "a",
# CHECK-NEXT: "insertText": "a",
# CHECK-NEXT: "insertTextFormat": 1,
# CHECK-NEXT: "kind": 5,
# CHECK-NEXT: "label": " a",
# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
# CHECK-NEXT: "sortText": "{{.*}}"
# CHECK: ]
# CHECK-NEXT: }
Content-Length: 1024

{"jsonrpc":"2.0","id":5,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message which reads beyond the end of the stream.
#
# Ensure this is the last test in the file!
# STDERR: Input was aborted. Read only {{[0-9]+}} bytes of expected {{[0-9]+}}.

# RUN: not clangd -pretty -sync -enable-test-uri-scheme < %s | FileCheck -strict-whitespace %s
# RUN: not clangd -pretty -sync -enable-test-uri-scheme < %s 2>&1 | FileCheck -check-prefix=STDERR %s
# vim: fileformat=dos
# It is absolutely vital that this file has CRLF line endings.
#
# Note that we invert the test because we intent to let clangd exit prematurely.
#
# Test protocol parsing
Content-Length: 125
Content-Type: application/vscode-jsonrpc; charset-utf-8
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
# Test message with Content-Type after Content-Length
#
# CHECK: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK: }
Content-Length: 246
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"struct fake { int a, bb, ccc; int f(int i, const float f) const; };\nint main() {\n fake f;\n f.\n}\n"}}}
Content-Length: 104
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp"}}}
Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 146
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with Content-Type before Content-Length
#
# CHECK: "id": 1,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "isIncomplete": false,
# CHECK-NEXT: "items": [
# CHECK: "filterText": "a",
# CHECK-NEXT: "insertText": "a",
# CHECK-NEXT: "insertTextFormat": 1,
# CHECK-NEXT: "kind": 5,
# CHECK-NEXT: "label": " a",
# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
# CHECK-NEXT: "sortText": "{{.*}}"
# CHECK: ]
# CHECK-NEXT: }
X-Test: Testing
Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 146
Content-Type: application/vscode-jsonrpc; charset-utf-8
X-Testing: Test
{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 10
Content-Length: 146
{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with duplicate Content-Length headers
#
# CHECK: "id": 3,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "isIncomplete": false,
# CHECK-NEXT: "items": [
# CHECK: "filterText": "a",
# CHECK-NEXT: "insertText": "a",
# CHECK-NEXT: "insertTextFormat": 1,
# CHECK-NEXT: "kind": 5,
# CHECK-NEXT: "label": " a",
# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
# CHECK-NEXT: "sortText": "{{.*}}"
# CHECK: ]
# CHECK-NEXT: }
# STDERR: Warning: Duplicate Content-Length header received. The previous value for this message (10) was ignored.
Content-Type: application/vscode-jsonrpc; charset-utf-8
Content-Length: 10
{"jsonrpc":"2.0","id":4,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with malformed Content-Length
#
# STDERR: JSON parse error
# Ensure we recover by sending another (valid) message
Content-Length: 146
{"jsonrpc":"2.0","id":5,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message with Content-Type before Content-Length
#
# CHECK: "id": 5,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "isIncomplete": false,
# CHECK-NEXT: "items": [
# CHECK: "filterText": "a",
# CHECK-NEXT: "insertText": "a",
# CHECK-NEXT: "insertTextFormat": 1,
# CHECK-NEXT: "kind": 5,
# CHECK-NEXT: "label": " a",
# CHECK-NEXT: "score": {{[0-9]+.[0-9]+}},
# CHECK-NEXT: "sortText": "{{.*}}"
# CHECK: ]
# CHECK-NEXT: }
Content-Length: 1024
{"jsonrpc":"2.0","id":5,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:/main.cpp"},"position":{"line":3,"character":5}}}
# Test message which reads beyond the end of the stream.
#
# Ensure this is the last test in the file!
# STDERR: Input was aborted. Read only {{[0-9]+}} bytes of expected {{[0-9]+}}.
14 changes: 7 additions & 7 deletions clang-tools-extra/clangd/test/too_large.test
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# RUN: not clangd -sync < %s 2>&1 | FileCheck -check-prefix=STDERR %s
# vim: fileformat=dos
# It is absolutely vital that this file has CRLF line endings.
#
Content-Length: 2147483648

# STDERR: Refusing to read message
# RUN: not clangd -sync < %s 2>&1 | FileCheck -check-prefix=STDERR %s
# vim: fileformat=dos
# It is absolutely vital that this file has CRLF line endings.
#
Content-Length: 2147483648
# STDERR: Refusing to read message
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: not clang-query --invalid-arg 2>&1 | FileCheck %s

// CHECK: error: clang-query{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: 'clang-query{{(\.exe)?}} --help'
// CHECK: error: clang-query{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: '{{.*}}clang-query{{(\.exe)?}} --help'
// CHECK-NEXT: clang-query{{(\.exe)?}}: Did you mean '--extra-arg'?
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,9 @@ struct prefer_underscore_version_flip {
size_t find(const char *s, size_t pos = 0) const;
};

struct prefer_underscore_version_inherit : public string_like {
bool startsWith(const char *s) const;
};

void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
string_like sl, string_like_camel slc, prefer_underscore_version puv,
prefer_underscore_version_flip puvf,
prefer_underscore_version_inherit puvi) {
prefer_underscore_version_flip puvf) {
s.find("a") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of find() == 0
// CHECK-FIXES: s.starts_with("a");
Expand Down Expand Up @@ -153,12 +148,6 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
// CHECK-FIXES: puvf.starts_with("a");

// Here, the subclass has startsWith, the superclass has starts_with.
// We prefer the version from the subclass.
puvi.find("a") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use startsWith
// CHECK-FIXES: puvi.startsWith("a");

s.compare(0, 1, "a") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with instead of compare() == 0
// CHECK-FIXES: s.starts_with("a");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: not clang-tidy --invalid-arg 2>&1 | FileCheck %s

// CHECK: error: clang-tidy{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: 'clang-tidy{{(\.exe)?}} --help'
// CHECK: error: clang-tidy{{(\.exe)?}}: Unknown command line argument '--invalid-arg'. Try: '{{.*}}clang-tidy{{(\.exe)?}} --help'
// CHECK-NEXT: clang-tidy{{(\.exe)?}}: Did you mean '--extra-arg'?
25 changes: 25 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5505,6 +5505,31 @@ the configuration (without a prefix: ``Auto``).
}
}

.. _RemoveEmptyLinesInUnwrappedLines:

**RemoveEmptyLinesInUnwrappedLines** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <RemoveEmptyLinesInUnwrappedLines>`
Remove empty lines within unwrapped lines.

.. code-block:: c++

false: true:

int c vs. int c = a + b;

= a + b;

enum : unsigned vs. enum : unsigned {
AA = 0,
{ BB
AA = 0, } myEnum;
BB
} myEnum;

while ( vs. while (true) {
}
true) {
}

.. _RemoveParentheses:

**RemoveParentheses** (``RemoveParenthesesStyle``) :versionbadge:`clang-format 17` :ref:`¶ <RemoveParentheses>`
Expand Down
10 changes: 7 additions & 3 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ Non-comprehensive list of changes in this release
``__builtin_signbit`` can now be used in constant expressions.
- Plugins can now define custom attributes that apply to statements
as well as declarations.
- ``__builtin_abs`` function can now be used in constant expressions.

New Compiler Flags
------------------
Expand Down Expand Up @@ -418,7 +419,7 @@ Improvements to Clang's diagnostics
- The warning for an unsupported type for a named register variable is now phrased ``unsupported type for named register variable``,
instead of ``bad type for named register variable``. This makes it clear that the type is not supported at all, rather than being
suboptimal in some way the error fails to mention (#GH111550).

- Clang now emits a ``-Wdepredcated-literal-operator`` diagnostic, even if the
name was a reserved name, which we improperly allowed to suppress the
diagnostic.
Expand Down Expand Up @@ -537,6 +538,7 @@ Bug Fixes to C++ Support
certain situations. (#GH47400), (#GH90896)
- Fix erroneous templated array size calculation leading to crashes in generated code. (#GH41441)
- During the lookup for a base class name, non-type names are ignored. (#GH16855)
- Fix a crash when recovering an invalid expression involving an explicit object member conversion operator. (#GH112559)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -699,8 +701,10 @@ clang-format
- Adds ``BreakBinaryOperations`` option.
- Adds ``TemplateNames`` option.
- Adds ``AlignFunctionDeclarations`` option to ``AlignConsecutiveDeclarations``.
- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of multi-line comments
without touching their contents, renames ``false`` to ``Never``, and ``true`` to ``Always``.
- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of
multi-line comments without touching their contents, renames ``false`` to
``Never``, and ``true`` to ``Always``.
- Adds ``RemoveEmptyLinesInUnwrappedLines`` option.

libclang
--------
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 @@ -2980,7 +2980,7 @@ enum CXTypeKind {
CXType_Atomic = 177,
CXType_BTFTagAttributed = 178,

// HLSL Types
/* HLSL Types */
CXType_HLSLResource = 179,
CXType_HLSLAttributedResource = 180
};
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -6320,6 +6320,10 @@ class HLSLAttributedResourceType : public Type, public llvm::FoldingSetNode {
static bool classof(const Type *T) {
return T->getTypeClass() == HLSLAttributedResource;
}

// Returns handle type from HLSL resource, if the type is a resource
static const HLSLAttributedResourceType *
findHandleTypeOnResource(const Type *RT);
};

class TemplateTypeParmType : public Type, public llvm::FoldingSetNode {
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/AArch64SVEACLETypes.def
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ SVE_VECTOR_TYPE_FLOAT("__clang_svfloat64x2_t", "svfloat64x2_t", SveFloat64x2, Sv

SVE_VECTOR_TYPE_BFLOAT("__clang_svbfloat16x2_t", "svbfloat16x2_t", SveBFloat16x2, SveBFloat16x2Ty, 8, 16, 2)

SVE_VECTOR_TYPE_INT("__clang_svmfloat8x2_t", "svmfloat8x2_t", SveMFloat8x2, SveMFloat8x2Ty, 16, 8, 2, false)

//
// x3
//
Expand All @@ -158,6 +160,8 @@ SVE_VECTOR_TYPE_FLOAT("__clang_svfloat64x3_t", "svfloat64x3_t", SveFloat64x3, Sv

SVE_VECTOR_TYPE_BFLOAT("__clang_svbfloat16x3_t", "svbfloat16x3_t", SveBFloat16x3, SveBFloat16x3Ty, 8, 16, 3)

SVE_VECTOR_TYPE_INT("__clang_svmfloat8x3_t", "svmfloat8x3_t", SveMFloat8x3, SveMFloat8x3Ty, 16, 8, 3, false)

//
// x4
//
Expand All @@ -178,6 +182,8 @@ SVE_VECTOR_TYPE_FLOAT("__clang_svfloat64x4_t", "svfloat64x4_t", SveFloat64x4, Sv

SVE_VECTOR_TYPE_BFLOAT("__clang_svbfloat16x4_t", "svbfloat16x4_t", SveBFloat16x4, SveBFloat16x4Ty, 8, 16, 4)

SVE_VECTOR_TYPE_INT("__clang_svmfloat8x4_t", "svmfloat8x4_t", SveMFloat8x4, SveMFloat8x4Ty, 16, 8, 4, false)

SVE_PREDICATE_TYPE_ALL("__SVBool_t", "__SVBool_t", SveBool, SveBoolTy, 16, 1)
SVE_PREDICATE_TYPE_ALL("__clang_svboolx2_t", "svboolx2_t", SveBoolx2, SveBoolx2Ty, 16, 2)
SVE_PREDICATE_TYPE_ALL("__clang_svboolx4_t", "svboolx4_t", SveBoolx4, SveBoolx4Ty, 16, 4)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -2714,6 +2714,7 @@ def Abs : IntMathTemplate, LibBuiltin<"stdlib.h"> {
let Attributes = [NoThrow, Const];
let Prototype = "T(T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}

def Calloc : LibBuiltin<"stdlib.h"> {
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12499,7 +12499,7 @@ def warn_unsafe_buffer_variable : Warning<
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def warn_unsafe_buffer_operation : Warning<
"%select{unsafe pointer operation|unsafe pointer arithmetic|"
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of span::data|"
"unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of %1|"
"field %1 prone to unsafe buffer manipulation}0">,
InGroup<UnsafeBufferUsage>, DefaultIgnore;
def warn_unsafe_buffer_libc_call : Warning<
Expand Down
45 changes: 45 additions & 0 deletions clang/include/clang/Basic/StackExhaustionHandler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===--- StackExhaustionHandler.h - A utility for warning once when close to out
// of stack space -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines a utilitiy for warning once when close to out of stack space.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_BASIC_STACK_EXHAUSTION_HANDLER_H
#define LLVM_CLANG_BASIC_STACK_EXHAUSTION_HANDLER_H

#include "clang/Basic/Diagnostic.h"

namespace clang {
class StackExhaustionHandler {
public:
StackExhaustionHandler(DiagnosticsEngine &diags) : DiagsRef(diags) {}

/// Run some code with "sufficient" stack space. (Currently, at least 256K
/// is guaranteed). Produces a warning if we're low on stack space and
/// allocates more in that case. Use this in code that may recurse deeply to
/// avoid stack overflow.
void runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn);

/// Check to see if we're low on stack space and produce a warning if we're
/// low on stack space (Currently, at least 256Kis guaranteed).
void warnOnStackNearlyExhausted(SourceLocation Loc);

private:
/// Warn that the stack is nearly exhausted.
void warnStackExhausted(SourceLocation Loc);

DiagnosticsEngine &DiagsRef;
bool WarnedStackExhausted = false;
};
} // end namespace clang

#endif // LLVM_CLANG_BASIC_STACK_EXHAUSTION_HANDLER_H
3 changes: 2 additions & 1 deletion clang/include/clang/Driver/Distro.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class Distro {
UbuntuMantic,
UbuntuNoble,
UbuntuOracular,
UbuntuPlucky,
UnknownDistro
};

Expand Down Expand Up @@ -131,7 +132,7 @@ class Distro {
}

bool IsUbuntu() const {
return DistroVal >= UbuntuHardy && DistroVal <= UbuntuOracular;
return DistroVal >= UbuntuHardy && DistroVal <= UbuntuPlucky;
}

bool IsAlpineLinux() const { return DistroVal == AlpineLinux; }
Expand Down
15 changes: 11 additions & 4 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -3454,7 +3454,8 @@ def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>,
def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>;
def fno_struct_path_tbaa : Flag<["-"], "fno-struct-path-tbaa">, Group<f_Group>;
def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>;
def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>;
def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>,
Visibility<[ClangOption, FlangOption]>;
def fno_pointer_tbaa : Flag<["-"], "fno-pointer-tbaa">, Group<f_Group>;
def fno_temp_file : Flag<["-"], "fno-temp-file">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, HelpText<
Expand All @@ -3470,7 +3471,8 @@ def fno_verbose_asm : Flag<["-"], "fno-verbose-asm">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoNegativeFlag<CodeGenOpts<"AsmVerbose">>;
def fno_working_directory : Flag<["-"], "fno-working-directory">, Group<f_Group>;
def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>;
def fno_wrapv : Flag<["-"], "fno-wrapv">, Group<f_Group>,
Visibility<[ClangOption, FlangOption]>;
def fobjc_arc : Flag<["-"], "fobjc-arc">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Synthesize retain and release calls for Objective-C pointers">;
Expand Down Expand Up @@ -3966,7 +3968,8 @@ defm strict_vtable_pointers : BoolFOption<"strict-vtable-pointers",
"Enable optimizations based on the strict rules for"
" overwriting polymorphic C++ objects">,
NegFlag<SetFalse>>;
def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>;
def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group<f_Group>,
Visibility<[ClangOption, FlangOption]>;
def fpointer_tbaa : Flag<["-"], "fpointer-tbaa">, Group<f_Group>;
def fdriver_only : Flag<["-"], "fdriver-only">, Flags<[NoXarchOption]>,
Visibility<[ClangOption, CLOption, DXCOption]>,
Expand Down Expand Up @@ -4235,7 +4238,7 @@ defm virtual_function_elimination : BoolFOption<"virtual-function-elimination",
NegFlag<SetFalse>, BothFlags<[], [ClangOption, CLOption]>>;

def fwrapv : Flag<["-"], "fwrapv">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Treat signed integer overflow as two's complement">;
def fwritable_strings : Flag<["-"], "fwritable-strings">, Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -5387,6 +5390,10 @@ def mno_lasx : Flag<["-"], "mno-lasx">, Group<m_loongarch_Features_Group>,
let Flags = [TargetSpecific] in {
def msimd_EQ : Joined<["-"], "msimd=">, Group<m_loongarch_Features_Group>,
HelpText<"Select the SIMD extension(s) to be enabled in LoongArch either 'none', 'lsx', 'lasx'.">;
def mfrecipe : Flag<["-"], "mfrecipe">, Group<m_loongarch_Features_Group>,
HelpText<"Enable frecipe.{s/d} and frsqrte.{s/d}">;
def mno_frecipe : Flag<["-"], "mno-frecipe">, Group<m_loongarch_Features_Group>,
HelpText<"Disable frecipe.{s/d} and frsqrte.{s/d}">;
def mannotate_tablejump : Flag<["-"], "mannotate-tablejump">, Group<m_loongarch_Features_Group>,
HelpText<"Enable annotate table jump instruction to correlate it with the jump table.">;
def mno_annotate_tablejump : Flag<["-"], "mno-annotate-tablejump">, Group<m_loongarch_Features_Group>,
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3938,6 +3938,29 @@ struct FormatStyle {
/// \version 14
bool RemoveBracesLLVM;

/// Remove empty lines within unwrapped lines.
/// \code
/// false: true:
///
/// int c vs. int c = a + b;
///
/// = a + b;
///
/// enum : unsigned vs. enum : unsigned {
/// AA = 0,
/// { BB
/// AA = 0, } myEnum;
/// BB
/// } myEnum;
///
/// while ( vs. while (true) {
/// }
/// true) {
/// }
/// \endcode
/// \version 20
bool RemoveEmptyLinesInUnwrappedLines;

/// Types of redundant parentheses to remove.
enum RemoveParenthesesStyle : int8_t {
/// Do not remove parentheses.
Expand Down Expand Up @@ -5232,6 +5255,8 @@ struct FormatStyle {
RawStringFormats == R.RawStringFormats &&
ReferenceAlignment == R.ReferenceAlignment &&
RemoveBracesLLVM == R.RemoveBracesLLVM &&
RemoveEmptyLinesInUnwrappedLines ==
R.RemoveEmptyLinesInUnwrappedLines &&
RemoveParentheses == R.RemoveParentheses &&
RemoveSemicolon == R.RemoveSemicolon &&
RequiresClausePosition == R.RequiresClausePosition &&
Expand Down
6 changes: 2 additions & 4 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include "clang/Basic/PragmaKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/StackExhaustionHandler.h"
#include "clang/Basic/TemplateKinds.h"
#include "clang/Basic/TokenKinds.h"
#include "clang/Basic/TypeTraits.h"
Expand Down Expand Up @@ -546,9 +547,6 @@ class Sema final : public SemaBase {
/// Print out statistics about the semantic analysis.
void PrintStats() const;

/// Warn that the stack is nearly exhausted.
void warnStackExhausted(SourceLocation Loc);

/// Run some code with "sufficient" stack space. (Currently, at least 256K is
/// guaranteed). Produces a warning if we're low on stack space and allocates
/// more in that case. Use this in code that may recurse deeply (for example,
Expand Down Expand Up @@ -1183,7 +1181,7 @@ class Sema final : public SemaBase {
std::optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
bool WarnedDarwinSDKInfoMissing = false;

bool WarnedStackExhausted = false;
StackExhaustionHandler StackHandler;

Sema(const Sema &) = delete;
void operator=(const Sema &) = delete;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ enum PredefinedTypeIDs {
///
/// Type IDs for non-predefined types will start at
/// NUM_PREDEF_TYPE_IDs.
const unsigned NUM_PREDEF_TYPE_IDS = 506;
const unsigned NUM_PREDEF_TYPE_IDS = 509;

// Ensure we do not overrun the predefined types we reserved
// in the enum PredefinedTypeIDs above.
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/OpenCLOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/StackExhaustionHandler.h"
#include "clang/Basic/Version.h"
#include "clang/Lex/ExternalPreprocessorSource.h"
#include "clang/Lex/HeaderSearch.h"
Expand Down Expand Up @@ -445,7 +446,7 @@ class ASTReader
DiagnosticsEngine &Diags;
// Sema has duplicate logic, but SemaObj can sometimes be null so ASTReader
// has its own version.
bool WarnedStackExhausted = false;
StackExhaustionHandler StackHandler;

/// The semantic analysis object that will be processing the
/// AST files and the translation unit that uses it.
Expand Down Expand Up @@ -2180,7 +2181,8 @@ class ASTReader
/// Report a diagnostic.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const;

void warnStackExhausted(SourceLocation Loc);
void runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn);

IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID);

Expand Down
26 changes: 13 additions & 13 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,24 +362,24 @@ namespace clang {
template <typename TemplateParmDeclT>
Error importTemplateParameterDefaultArgument(const TemplateParmDeclT *D,
TemplateParmDeclT *ToD) {
Error Err = Error::success();
if (D->hasDefaultArgument()) {
if (D->defaultArgumentWasInherited()) {
auto *ToInheritedFrom = const_cast<TemplateParmDeclT *>(
importChecked(Err, D->getDefaultArgStorage().getInheritedFrom()));
if (Err)
return Err;
Expected<TemplateParmDeclT *> ToInheritedFromOrErr =
import(D->getDefaultArgStorage().getInheritedFrom());
if (!ToInheritedFromOrErr)
return ToInheritedFromOrErr.takeError();
TemplateParmDeclT *ToInheritedFrom = *ToInheritedFromOrErr;
if (!ToInheritedFrom->hasDefaultArgument()) {
// Resolve possible circular dependency between default value of the
// template argument and the template declaration.
const auto ToInheritedDefaultArg =
importChecked(Err, D->getDefaultArgStorage()
.getInheritedFrom()
->getDefaultArgument());
if (Err)
return Err;
Expected<TemplateArgumentLoc> ToInheritedDefaultArgOrErr =
import(D->getDefaultArgStorage()
.getInheritedFrom()
->getDefaultArgument());
if (!ToInheritedDefaultArgOrErr)
return ToInheritedDefaultArgOrErr.takeError();
ToInheritedFrom->setDefaultArgument(Importer.getToContext(),
ToInheritedDefaultArg);
*ToInheritedDefaultArgOrErr);
}
ToD->setInheritedDefaultArgument(ToD->getASTContext(),
ToInheritedFrom);
Expand All @@ -395,7 +395,7 @@ namespace clang {
*ToDefaultArgOrErr);
}
}
return Err;
return Error::success();
}

public:
Expand Down
22 changes: 16 additions & 6 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4132,10 +4132,16 @@ template <class Emitter>
bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
LocalScope<Emitter> RootScope(this);

// If we won't destroy the toplevel scope, check for memory leaks first.
if (!DestroyToplevelScope) {
if (!this->emitCheckAllocations(E))
return false;
}

auto maybeDestroyLocals = [&]() -> bool {
if (DestroyToplevelScope)
return RootScope.destroyLocals();
return true;
return RootScope.destroyLocals() && this->emitCheckAllocations(E);
return this->emitCheckAllocations(E);
};

// Void expressions.
Expand Down Expand Up @@ -4171,8 +4177,7 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
return this->emitRetValue(E) && maybeDestroyLocals();
}

(void)maybeDestroyLocals();
return false;
return maybeDestroyLocals() && this->emitCheckAllocations(E) && false;
}

template <class Emitter>
Expand Down Expand Up @@ -4214,7 +4219,8 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD,
DeclScope<Emitter> LS(this, VD);
if (!this->visit(VD->getAnyInitializer()))
return false;
return this->emitRet(VarT.value_or(PT_Ptr), VD) && LS.destroyLocals();
return this->emitRet(VarT.value_or(PT_Ptr), VD) && LS.destroyLocals() &&
this->emitCheckAllocations(VD);
}

LocalScope<Emitter> VDScope(this, VD);
Expand Down Expand Up @@ -4260,7 +4266,7 @@ bool Compiler<Emitter>::visitDeclAndReturn(const VarDecl *VD,
return false;
}

return VDScope.destroyLocals();
return VDScope.destroyLocals() && this->emitCheckAllocations(VD);
}

template <class Emitter>
Expand Down Expand Up @@ -4535,6 +4541,10 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
return VisitBuiltinCallExpr(E, Builtin::BI__builtin_operator_delete);
}
}
// Explicit calls to trivial destructors
if (const auto *DD = dyn_cast_if_present<CXXDestructorDecl>(FuncDecl);
DD && DD->isTrivial())
return true;

QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
std::optional<PrimType> T = classify(ReturnType);
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/ByteCode/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);

auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,
/*DestroyToplevelScope=*/Kind ==
ConstantExprKind::ClassTemplateArgument);
/*DestroyToplevelScope=*/true);
if (Res.isInvalid()) {
C.cleanup();
Stk.clearTo(StackSizeBefore);
Expand Down
17 changes: 0 additions & 17 deletions clang/lib/AST/ByteCode/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,10 @@ bool EvalEmitter::fallthrough(const LabelTy &Label) {
return true;
}

static bool checkReturnState(InterpState &S) {
return S.maybeDiagnoseDanglingAllocations();
}

template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
if (!isActive())
return true;

if (!checkReturnState(S))
return false;

using T = typename PrimConv<OpType>::T;
EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
return true;
Expand All @@ -159,9 +152,6 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;

if (!checkReturnState(S))
return false;

// Implicitly convert lvalue to rvalue, if requested.
if (ConvertResultToRValue) {
if (!Ptr.isZero() && !Ptr.isDereferencable())
Expand Down Expand Up @@ -194,16 +184,12 @@ template <> bool EvalEmitter::emitRet<PT_FnPtr>(const SourceInfo &Info) {
if (!isActive())
return true;

if (!checkReturnState(S))
return false;
// Function pointers cannot be converted to rvalues.
EvalResult.setFunctionPointer(S.Stk.pop<FunctionPointer>());
return true;
}

bool EvalEmitter::emitRetVoid(const SourceInfo &Info) {
if (!checkReturnState(S))
return false;
EvalResult.setValid();
return true;
}
Expand All @@ -216,9 +202,6 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;

if (!checkReturnState(S))
return false;

if (std::optional<APValue> APV =
Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
EvalResult.setValue(*APV);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1841,6 +1841,7 @@ bool Init(InterpState &S, CodePtr OpPC) {
assert(false);
return false;
}
Ptr.activate();
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
Expand All @@ -1852,6 +1853,7 @@ bool InitPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckInit(S, OpPC, Ptr))
return false;
Ptr.activate();
Ptr.initialize();
new (&Ptr.deref<T>()) T(Value);
return true;
Expand Down Expand Up @@ -3005,6 +3007,10 @@ static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {
return true;
}

static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {
return S.maybeDiagnoseDanglingAllocations();
}

/// Check if the initializer and storage types of a placement-new expression
/// match.
bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
Expand Down
21 changes: 21 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,20 @@ static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_abs(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
if (Val ==
APSInt(APInt::getSignedMinValue(Val.getBitWidth()), /*IsUnsigned=*/false))
return false;
if (Val.isNegative())
Val.negate();
pushInteger(S, Val, Call->getType());
return true;
}

static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
Expand Down Expand Up @@ -1808,6 +1822,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_abs:
case Builtin::BI__builtin_labs:
case Builtin::BI__builtin_llabs:
if (!interp__builtin_abs(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_popcount:
case Builtin::BI__builtin_popcountl:
case Builtin::BI__builtin_popcountll:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -836,3 +836,4 @@ def CheckNewTypeMismatchArray : Opcode {
}

def IsConstantContext: Opcode;
def CheckAllocations : Opcode;
10 changes: 7 additions & 3 deletions clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2512,7 +2512,8 @@ bool VarDecl::isUsableInConstantExpressions(const ASTContext &Context) const {
if (!DefVD->mightBeUsableInConstantExpressions(Context))
return false;
// ... and its initializer is a constant initializer.
if (Context.getLangOpts().CPlusPlus && !DefVD->hasConstantInitialization())
if ((Context.getLangOpts().CPlusPlus || getLangOpts().C23) &&
!DefVD->hasConstantInitialization())
return false;
// C++98 [expr.const]p1:
// An integral constant-expression can involve only [...] const variables
Expand Down Expand Up @@ -2619,8 +2620,11 @@ bool VarDecl::hasICEInitializer(const ASTContext &Context) const {
}

bool VarDecl::hasConstantInitialization() const {
// In C, all globals (and only globals) have constant initialization.
if (hasGlobalStorage() && !getASTContext().getLangOpts().CPlusPlus)
// In C, all globals and constexpr variables should have constant
// initialization. For constexpr variables in C check that initializer is a
// constant initializer because they can be used in constant expressions.
if (hasGlobalStorage() && !getASTContext().getLangOpts().CPlusPlus &&
!isConstexpr())
return true;

// In C++, it depends on whether the evaluation at the point of definition
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1989,7 +1989,7 @@ Expr *CastExpr::getSubExprAsWritten() {
SubExpr = IgnoreExprNodes(cast<CXXConstructExpr>(SubExpr)->getArg(0),
ignoreImplicitSemaNodes);
} else if (E->getCastKind() == CK_UserDefinedConversion) {
assert((isa<CXXMemberCallExpr>(SubExpr) || isa<BlockExpr>(SubExpr)) &&
assert((isa<CallExpr, BlockExpr>(SubExpr)) &&
"Unexpected SubExpr for CK_UserDefinedConversion.");
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SubExpr))
SubExpr = MCE->getImplicitObjectArgument();
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13098,6 +13098,20 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(Val.popcount() % 2, E);
}

case Builtin::BI__builtin_abs:
case Builtin::BI__builtin_labs:
case Builtin::BI__builtin_llabs: {
APSInt Val;
if (!EvaluateInteger(E->getArg(0), Val, Info))
return false;
if (Val == APSInt(APInt::getSignedMinValue(Val.getBitWidth()),
/*IsUnsigned=*/false))
return false;
if (Val.isNegative())
Val.negate();
return Success(Val, E);
}

case Builtin::BI__builtin_popcount:
case Builtin::BI__builtin_popcountl:
case Builtin::BI__builtin_popcountll:
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5335,3 +5335,18 @@ std::string FunctionEffectWithCondition::description() const {
Result += "(expr)";
return Result;
}

const HLSLAttributedResourceType *
HLSLAttributedResourceType::findHandleTypeOnResource(const Type *RT) {
// If the type RT is an HLSL resource class, the first field must
// be the resource handle of type HLSLAttributedResourceType
const clang::Type *Ty = RT->getUnqualifiedDesugaredType();
if (const RecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (!RD->fields().empty()) {
const auto &FirstFD = RD->fields().begin();
return dyn_cast<HLSLAttributedResourceType>(
FirstFD->getType().getTypePtr());
}
}
return nullptr;
}
7 changes: 5 additions & 2 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1499,8 +1499,11 @@ class DataInvocationGadget : public WarningGadget {
}

static Matcher matcher() {
Matcher callExpr = cxxMemberCallExpr(
callee(cxxMethodDecl(hasName("data"), ofClass(hasName("std::span")))));

Matcher callExpr = cxxMemberCallExpr(callee(
cxxMethodDecl(hasName("data"),
ofClass(anyOf(hasName("std::span"), hasName("std::array"),
hasName("std::vector"))))));
return stmt(
explicitCastExpr(anyOf(has(callExpr), has(parenExpr(has(callExpr)))))
.bind(OpTag));
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ add_clang_library(clangBasic
SourceManager.cpp
SourceMgrAdapter.cpp
Stack.cpp
StackExhaustionHandler.cpp
TargetID.cpp
TargetInfo.cpp
Targets.cpp
Expand Down
35 changes: 35 additions & 0 deletions clang/lib/Basic/StackExhaustionHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===--- StackExhaustionHandler.cpp - - A utility for warning once when close
// to out of stack space -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines a utilitiy for warning once when close to out of stack space.
///
//===----------------------------------------------------------------------===//

#include "clang/Basic/StackExhaustionHandler.h"
#include "clang/Basic/Stack.h"

void clang::StackExhaustionHandler::runWithSufficientStackSpace(
SourceLocation Loc, llvm::function_ref<void()> Fn) {
clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn);
}

void clang::StackExhaustionHandler::warnOnStackNearlyExhausted(
SourceLocation Loc) {
if (isStackNearlyExhausted())
warnStackExhausted(Loc);
}

void clang::StackExhaustionHandler::warnStackExhausted(SourceLocation Loc) {
// Only warn about this once.
if (!WarnedStackExhausted) {
DiagsRef.Report(Loc, diag::warn_stack_exhausted);
WarnedStackExhausted = true;
}
}
10 changes: 10 additions & 0 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ bool RISCVTargetInfo::validateAsmConstraint(
case 'S': // A symbol or label reference with a constant offset
Info.setAllowsRegister();
return true;
case 'c':
// A RVC register - GPR or FPR
if (Name[1] == 'r' || Name[1] == 'f') {
Info.setAllowsRegister();
Name += 1;
return true;
}
return false;
case 'v':
// A vector register.
if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {
Expand All @@ -114,6 +122,8 @@ bool RISCVTargetInfo::validateAsmConstraint(
std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
std::string R;
switch (*Constraint) {
// c* and v* are two-letter constraints on RISC-V.
case 'c':
case 'v':
R = std::string("^") + std::string(Constraint, 2);
Constraint += 1;
Expand Down
49 changes: 22 additions & 27 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,24 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
// Can't find the field referenced by the "counted_by" attribute.
return nullptr;

if (isa<DeclRefExpr>(Base))
// The whole struct is specificed in the __bdos. The calculation of the
// whole size of the structure can be done in two ways:
//
// 1) sizeof(struct S) + count * sizeof(typeof(fam))
// 2) offsetof(struct S, fam) + count * sizeof(typeof(fam))
//
// The first will add additional padding after the end of the array,
// allocation while the second method is more precise, but not quite
// expected from programmers. See
// https://lore.kernel.org/lkml/ZvV6X5FPBBW7CO1f@archlinux/ for a
// discussion of the topic.
//
// GCC isn't (currently) able to calculate __bdos on a pointer to the whole
// structure. Therefore, because of the above issue, we'll choose to match
// what GCC does for consistency's sake.
return nullptr;

// Build a load of the counted_by field.
bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
Value *CountedByInst = EmitLoadOfCountedByField(Base, FAMDecl, CountedByFD);
Expand Down Expand Up @@ -1043,32 +1061,9 @@ CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
llvm::Constant *ElemSize =
llvm::ConstantInt::get(ResType, Size.getQuantity(), IsSigned);
Value *FAMSize =
Value *Res =
Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
FAMSize = Builder.CreateIntCast(FAMSize, ResType, IsSigned);
Value *Res = FAMSize;

if (isa<DeclRefExpr>(Base)) {
// The whole struct is specificed in the __bdos.
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);

// Get the offset of the FAM.
llvm::Constant *FAMOffset = ConstantInt::get(ResType, Offset, IsSigned);
Value *OffsetAndFAMSize =
Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);

// Get the full size of the struct.
llvm::Constant *SizeofStruct =
ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);

// max(sizeof(struct s),
// offsetof(struct s, array) + p->count * sizeof(*p->array))
Res = IsSigned
? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
OffsetAndFAMSize, SizeofStruct)
: Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
OffsetAndFAMSize, SizeofStruct);
}
Res = Builder.CreateIntCast(Res, ResType, IsSigned);

// A negative \p IdxInst or \p CountedByInst means that the index lands
// outside of the flexible array member. If that's the case, we want to
Expand Down Expand Up @@ -5641,10 +5636,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm::Type *ArgTys[] = {Arg0->getType(), I8PTy, Int32Ty, Int32Ty};
llvm::FunctionType *FTy = llvm::FunctionType::get(
Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
Value *BCast = Builder.CreatePointerCast(Arg1, I8PTy);
Value *ACast = Builder.CreateAddrSpaceCast(Arg1, I8PTy);
return RValue::get(
EmitRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name),
{Arg0, BCast, PacketSize, PacketAlign}));
{Arg0, ACast, PacketSize, PacketAlign}));
} else {
assert(4 == E->getNumArgs() &&
"Illegal number of parameters to pipe function");
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CGDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,14 @@ CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
if (Decls[i])
EmitRuntimeCall(Decls[i]);

if (getLangOpts().HLSL) {
CGHLSLRuntime &CGHLSL = CGM.getHLSLRuntime();
if (CGHLSL.needsResourceBindingInitFn()) {
llvm::Function *ResInitFn = CGHLSL.createResourceBindingInitFn();
Builder.CreateCall(llvm::FunctionCallee(ResInitFn), {});
}
}

Scope.ForceCleanup();

if (ExitBlock) {
Expand Down
90 changes: 90 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
#include "TargetInfo.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/TargetOptions.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Alignment.h"

#include "llvm/Support/FormatVariadic.h"

using namespace clang;
Expand Down Expand Up @@ -489,3 +494,88 @@ void CGHLSLRuntime::generateGlobalCtorDtorCalls() {
GV->eraseFromParent();
}
}

void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD,
llvm::GlobalVariable *GV) {
// If the global variable has resource binding, add it to the list of globals
// that need resource binding initialization.
const HLSLResourceBindingAttr *RBA = VD->getAttr<HLSLResourceBindingAttr>();
if (!RBA)
return;

if (!HLSLAttributedResourceType::findHandleTypeOnResource(
VD->getType().getTypePtr()))
// FIXME: Only simple declarations of resources are supported for now.
// Arrays of resources or resources in user defined classes are
// not implemented yet.
return;

ResourcesToBind.emplace_back(VD, GV);
}

bool CGHLSLRuntime::needsResourceBindingInitFn() {
return !ResourcesToBind.empty();
}

llvm::Function *CGHLSLRuntime::createResourceBindingInitFn() {
// No resources to bind
assert(needsResourceBindingInitFn() && "no resources to bind");

LLVMContext &Ctx = CGM.getLLVMContext();
llvm::Type *Int1Ty = llvm::Type::getInt1Ty(Ctx);

llvm::Function *InitResBindingsFunc =
llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, false),
llvm::GlobalValue::InternalLinkage,
"_init_resource_bindings", CGM.getModule());

llvm::BasicBlock *EntryBB =
llvm::BasicBlock::Create(Ctx, "entry", InitResBindingsFunc);
CGBuilderTy Builder(CGM, Ctx);
const DataLayout &DL = CGM.getModule().getDataLayout();
Builder.SetInsertPoint(EntryBB);

for (const auto &[VD, GV] : ResourcesToBind) {
for (Attr *A : VD->getAttrs()) {
HLSLResourceBindingAttr *RBA = dyn_cast<HLSLResourceBindingAttr>(A);
if (!RBA)
continue;

const HLSLAttributedResourceType *AttrResType =
HLSLAttributedResourceType::findHandleTypeOnResource(
VD->getType().getTypePtr());

// FIXME: Only simple declarations of resources are supported for now.
// Arrays of resources or resources in user defined classes are
// not implemented yet.
assert(AttrResType != nullptr &&
"Resource class must have a handle of HLSLAttributedResourceType");

llvm::Type *TargetTy =
CGM.getTargetCodeGenInfo().getHLSLType(CGM, AttrResType);
assert(TargetTy != nullptr &&
"Failed to convert resource handle to target type");

auto *Space = llvm::ConstantInt::get(CGM.IntTy, RBA->getSpaceNumber());
auto *Slot = llvm::ConstantInt::get(CGM.IntTy, RBA->getSlotNumber());
// FIXME: resource arrays are not yet implemented
auto *Range = llvm::ConstantInt::get(CGM.IntTy, 1);
auto *Index = llvm::ConstantInt::get(CGM.IntTy, 0);
// FIXME: NonUniformResourceIndex bit is not yet implemented
auto *NonUniform = llvm::ConstantInt::get(Int1Ty, false);
llvm::Value *Args[] = {Space, Slot, Range, Index, NonUniform};

llvm::Value *CreateHandle = Builder.CreateIntrinsic(
/*ReturnType=*/TargetTy, getCreateHandleFromBindingIntrinsic(), Args,
nullptr, Twine(VD->getName()).concat("_h"));

llvm::Value *HandleRef =
Builder.CreateStructGEP(GV->getValueType(), GV, 0);
Builder.CreateAlignedStore(CreateHandle, HandleRef,
HandleRef->getPointerAlignment(DL));
}
}

Builder.CreateRetVoid();
return InitResBindingsFunc;
}
9 changes: 9 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane)
GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane)

GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, handle_fromBinding)

//===----------------------------------------------------------------------===//
// End of reserved area for HLSL intrinsic getters.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -137,6 +139,10 @@ class CGHLSLRuntime {

void emitEntryFunction(const FunctionDecl *FD, llvm::Function *Fn);
void setHLSLFunctionAttributes(const FunctionDecl *FD, llvm::Function *Fn);
void handleGlobalVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Var);

bool needsResourceBindingInitFn();
llvm::Function *createResourceBindingInitFn();

private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
Expand All @@ -148,6 +154,9 @@ class CGHLSLRuntime {
void addBufferDecls(const DeclContext *DC, Buffer &CB);
llvm::Triple::ArchType getArch();
llvm::SmallVector<Buffer> Buffers;

llvm::SmallVector<std::pair<const VarDecl *, llvm::GlobalVariable *>>
ResourcesToBind;
};

} // namespace CodeGen
Expand Down
15 changes: 5 additions & 10 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ CodeGenModule::CodeGenModule(ASTContext &C,
: Context(C), LangOpts(C.getLangOpts()), FS(FS), HeaderSearchOpts(HSO),
PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags),
Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
VMContext(M.getContext()), VTables(*this),
VMContext(M.getContext()), VTables(*this), StackHandler(diags),
SanitizerMD(new SanitizerMetadata(*this)) {

// Initialize the type cache.
Expand Down Expand Up @@ -1595,17 +1595,9 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type) {
getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
}

void CodeGenModule::warnStackExhausted(SourceLocation Loc) {
// Only warn about this once.
if (!WarnedStackExhausted) {
getDiags().Report(Loc, diag::warn_stack_exhausted);
WarnedStackExhausted = true;
}
}

void CodeGenModule::runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn) {
clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn);
StackHandler.runWithSufficientStackSpace(Loc, Fn);
}

llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) {
Expand Down Expand Up @@ -5634,6 +5626,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
getCUDARuntime().handleVarRegistration(D, *GV);
}

if (LangOpts.HLSL)
getHLSLRuntime().handleGlobalVarDefinition(D, GV);

GV->setInitializer(Init);
if (emitter)
emitter->finalize(GV);
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/NoSanitizeList.h"
#include "clang/Basic/ProfileList.h"
#include "clang/Basic/StackExhaustionHandler.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/XRayLists.h"
#include "clang/Lex/PreprocessorOptions.h"
Expand Down Expand Up @@ -336,7 +337,7 @@ class CodeGenModule : public CodeGenTypeCache {
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
InstrProfStats PGOStats;
std::unique_ptr<llvm::SanitizerStatReport> SanStats;
bool WarnedStackExhausted = false;
StackExhaustionHandler StackHandler;

// A set of references that have only been seen via a weakref so far. This is
// used to remove the weak of the reference if we ever see a direct reference
Expand Down Expand Up @@ -1298,9 +1299,6 @@ class CodeGenModule : public CodeGenTypeCache {
/// Print out an error that codegen doesn't support the specified decl yet.
void ErrorUnsupported(const Decl *D, const char *Type);

/// Warn that the stack is nearly exhausted.
void warnStackExhausted(SourceLocation Loc);

/// Run some code with "sufficient" stack space. (Currently, at least 256K is
/// guaranteed). Produces a warning if we're low on stack space and allocates
/// more in that case. Use this in code that may recurse deeply to avoid stack
Expand Down
37 changes: 21 additions & 16 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3437,7 +3437,7 @@ class ItaniumRTTIBuilder {
llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty);

/// BuildVTablePointer - Build the vtable pointer for the given type.
void BuildVTablePointer(const Type *Ty);
void BuildVTablePointer(const Type *Ty, llvm::Constant *StorageAddress);

/// BuildSIClassTypeInfo - Build an abi::__si_class_type_info, used for single
/// inheritance, according to the Itanium C++ ABI, 2.9.5p6b.
Expand Down Expand Up @@ -3834,7 +3834,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) {
return true;
}

void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty,
llvm::Constant *StorageAddress) {
// abi::__class_type_info.
static const char * const ClassTypeInfo =
"_ZTVN10__cxxabiv117__class_type_infoE";
Expand Down Expand Up @@ -3981,9 +3982,12 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
VTable, Two);
}

if (auto &Schema = CGM.getCodeGenOpts().PointerAuth.CXXTypeInfoVTablePointer)
VTable = CGM.getConstantSignedPointer(VTable, Schema, nullptr, GlobalDecl(),
QualType(Ty, 0));
if (const auto &Schema =
CGM.getCodeGenOpts().PointerAuth.CXXTypeInfoVTablePointer)
VTable = CGM.getConstantSignedPointer(
VTable, Schema,
Schema.isAddressDiscriminated() ? StorageAddress : nullptr,
GlobalDecl(), QualType(Ty, 0));

Fields.push_back(VTable);
}
Expand Down Expand Up @@ -4099,8 +4103,18 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
llvm::GlobalVariable::LinkageTypes Linkage,
llvm::GlobalValue::VisibilityTypes Visibility,
llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass) {
SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
llvm::Module &M = CGM.getModule();
llvm::GlobalVariable *OldGV = M.getNamedGlobal(Name);
// int8 is an arbitrary type to be replaced later with replaceInitializer.
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(M, CGM.Int8Ty, /*isConstant=*/true, Linkage,
/*Initializer=*/nullptr, Name);

// Add the vtable pointer.
BuildVTablePointer(cast<Type>(Ty));
BuildVTablePointer(cast<Type>(Ty), GV);

// And the name.
llvm::GlobalVariable *TypeName = GetAddrOfTypeName(Ty, Linkage);
Expand Down Expand Up @@ -4218,16 +4232,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
llvm_unreachable("HLSL doesn't support RTTI");
}

llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);

SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty, Out);
llvm::Module &M = CGM.getModule();
llvm::GlobalVariable *OldGV = M.getNamedGlobal(Name);
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(M, Init->getType(),
/*isConstant=*/true, Linkage, Init, Name);
GV->replaceInitializer(llvm::ConstantStruct::getAnon(Fields));

// Export the typeinfo in the same circumstances as the vtable is exported.
auto GVDLLStorageClass = DLLStorageClass;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/Distro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) {
.Case("mantic", Distro::UbuntuMantic)
.Case("noble", Distro::UbuntuNoble)
.Case("oracular", Distro::UbuntuOracular)
.Case("plucky", Distro::UbuntuPlucky)
.Default(Distro::UnknownDistro);
return Version;
}
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D,
} else /*-mno-lasx*/
Features.push_back("-lasx");
}

// Select frecipe feature determined by -m[no-]frecipe.
if (const Arg *A =
Args.getLastArg(options::OPT_mfrecipe, options::OPT_mno_frecipe)) {
if (A->getOption().matches(options::OPT_mfrecipe))
Features.push_back("+frecipe");
else
Features.push_back("-frecipe");
}
}

std::string loongarch::postProcessTargetCPUString(const std::string &CPU,
Expand Down
31 changes: 17 additions & 14 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3595,7 +3595,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
StringRef Value = A->getValue();
if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() &&
!EffectiveTriple.isARM() && !EffectiveTriple.isThumb() &&
!EffectiveTriple.isRISCV())
!EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() ||
Expand Down Expand Up @@ -3635,7 +3635,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
<< A->getOption().getName() << Value << "sysreg global";
return;
}
if (EffectiveTriple.isRISCV()) {
if (EffectiveTriple.isRISCV() || EffectiveTriple.isPPC()) {
if (Value != "tls" && Value != "global") {
D.Diag(diag::err_drv_invalid_value_with_suggestion)
<< A->getOption().getName() << Value << "tls global";
Expand All @@ -3656,7 +3656,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
StringRef Value = A->getValue();
if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() &&
!EffectiveTriple.isARM() && !EffectiveTriple.isThumb() &&
!EffectiveTriple.isRISCV())
!EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
int Offset;
Expand All @@ -3676,7 +3676,7 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_reg_EQ)) {
StringRef Value = A->getValue();
if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() &&
!EffectiveTriple.isRISCV())
!EffectiveTriple.isRISCV() && !EffectiveTriple.isPPC())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getAsString(Args) << TripleStr;
if (EffectiveTriple.isX86() && (Value != "fs" && Value != "gs")) {
Expand All @@ -3693,6 +3693,16 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
<< A->getOption().getName() << Value << "tp";
return;
}
if (EffectiveTriple.isPPC64() && Value != "r13") {
D.Diag(diag::err_drv_invalid_value_with_suggestion)
<< A->getOption().getName() << Value << "r13";
return;
}
if (EffectiveTriple.isPPC32() && Value != "r2") {
D.Diag(diag::err_drv_invalid_value_with_suggestion)
<< A->getOption().getName() << Value << "r2";
return;
}
A->render(Args, CmdArgs);
}

Expand Down Expand Up @@ -6914,16 +6924,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,

Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ);

// -fno-strict-overflow implies -fwrapv if it isn't disabled, but
// -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
if (A->getOption().matches(options::OPT_fwrapv))
CmdArgs.push_back("-fwrapv");
} else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
options::OPT_fno_strict_overflow)) {
if (A->getOption().matches(options::OPT_fno_strict_overflow))
CmdArgs.push_back("-fwrapv");
}
// Handle -f[no-]wrapv and -f[no-]strict-overflow, which are used by both
// clang and flang.
renderCommonIntegerOverflowOptions(Args, CmdArgs);

Args.AddLastArg(CmdArgs, options::OPT_ffinite_loops,
options::OPT_fno_finite_loops);
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3048,3 +3048,17 @@ bool tools::shouldRecordCommandLine(const ToolChain &TC,

return FRecordCommandLine || TC.UseDwarfDebugFlags() || GRecordCommandLine;
}

void tools::renderCommonIntegerOverflowOptions(const ArgList &Args,
ArgStringList &CmdArgs) {
// -fno-strict-overflow implies -fwrapv if it isn't disabled, but
// -fstrict-overflow won't turn off an explicitly enabled -fwrapv.
if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) {
if (A->getOption().matches(options::OPT_fwrapv))
CmdArgs.push_back("-fwrapv");
} else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow,
options::OPT_fno_strict_overflow)) {
if (A->getOption().matches(options::OPT_fno_strict_overflow))
CmdArgs.push_back("-fwrapv");
}
}
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/CommonArgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,9 @@ bool shouldRecordCommandLine(const ToolChain &TC,
bool &FRecordCommandLine,
bool &GRecordCommandLine);

void renderCommonIntegerOverflowOptions(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs);

} // end namespace tools
} // end namespace driver
} // end namespace clang
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/Flang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,8 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
}
}

renderCommonIntegerOverflowOptions(Args, CmdArgs);

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("ReferenceAlignment", Style.ReferenceAlignment);
IO.mapOptional("ReflowComments", Style.ReflowComments);
IO.mapOptional("RemoveBracesLLVM", Style.RemoveBracesLLVM);
IO.mapOptional("RemoveEmptyLinesInUnwrappedLines",
Style.RemoveEmptyLinesInUnwrappedLines);
IO.mapOptional("RemoveParentheses", Style.RemoveParentheses);
IO.mapOptional("RemoveSemicolon", Style.RemoveSemicolon);
IO.mapOptional("RequiresClausePosition", Style.RequiresClausePosition);
Expand Down Expand Up @@ -1582,6 +1584,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
LLVMStyle.ReflowComments = FormatStyle::RCS_Always;
LLVMStyle.RemoveBracesLLVM = false;
LLVMStyle.RemoveEmptyLinesInUnwrappedLines = false;
LLVMStyle.RemoveParentheses = FormatStyle::RPS_Leave;
LLVMStyle.RemoveSemicolon = false;
LLVMStyle.RequiresClausePosition = FormatStyle::RCPS_OwnLine;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5509,8 +5509,10 @@ static bool isAllmanLambdaBrace(const FormatToken &Tok) {
bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
const FormatToken &Right) const {
const FormatToken &Left = *Right.Previous;
if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0)
if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0 &&
(!Style.RemoveEmptyLinesInUnwrappedLines || &Right == Line.First)) {
return true;
}

if (Style.BreakFunctionDefinitionParameters && Line.MightBeFunctionDecl &&
Line.mightBeFunctionDefinition() && Left.MightBeFunctionDeclParen &&
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2504,6 +2504,11 @@ bool UnwrappedLineParser::parseBracedList(bool IsAngleBracket, bool IsEnum) {
// Assume there are no blocks inside a braced init list apart
// from the ones we explicitly parse out (like lambdas).
FormatTok->setBlockKind(BK_BracedInit);
if (!IsAngleBracket) {
auto *Prev = FormatTok->Previous;
if (Prev && Prev->is(tok::greater))
Prev->setFinalizedType(TT_TemplateCloser);
}
nextToken();
parseBracedList();
break;
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Sema/AnalysisBasedWarnings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2279,9 +2279,18 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
QualType srcType = ECE->getSubExpr()->getType();
const uint64_t sSize =
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());

if (sSize >= dSize)
return;

if (const auto *CE = dyn_cast<CXXMemberCallExpr>(
ECE->getSubExpr()->IgnoreParens())) {
D = CE->getMethodDecl();
}

if (!D)
return;

MsgParam = 4;
}
Loc = Operation->getBeginLoc();
Expand Down
12 changes: 2 additions & 10 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr),
LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr),
CurScope(nullptr), Ident_super(nullptr),
StackHandler(Diags), CurScope(nullptr), Ident_super(nullptr),
AMDGPUPtr(std::make_unique<SemaAMDGPU>(*this)),
ARMPtr(std::make_unique<SemaARM>(*this)),
AVRPtr(std::make_unique<SemaAVR>(*this)),
Expand Down Expand Up @@ -562,17 +562,9 @@ Sema::~Sema() {
SemaPPCallbackHandler->reset();
}

void Sema::warnStackExhausted(SourceLocation Loc) {
// Only warn about this once.
if (!WarnedStackExhausted) {
Diag(Loc, diag::warn_stack_exhausted);
WarnedStackExhausted = true;
}
}

void Sema::runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn) {
clang::runWithSufficientStackSpace([&] { warnStackExhausted(Loc); }, Fn);
StackHandler.runWithSufficientStackSpace(Loc, Fn);
}

bool Sema::makeUnavailableInSystemHeader(SourceLocation loc,
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/SemaFunctionEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,7 @@ bool Sema::FunctionEffectDiff::shouldDiagnoseConversion(
// matching is better.
return true;
}
break;
case FunctionEffect::Kind::Blocking:
case FunctionEffect::Kind::Allocating:
return false;
Expand All @@ -1563,6 +1564,7 @@ bool Sema::FunctionEffectDiff::shouldDiagnoseRedeclaration(
// All these forms of mismatches are diagnosed.
return true;
}
break;
case FunctionEffect::Kind::Blocking:
case FunctionEffect::Kind::Allocating:
return false;
Expand Down Expand Up @@ -1592,7 +1594,7 @@ Sema::FunctionEffectDiff::shouldDiagnoseMethodOverride(
case Kind::ConditionMismatch:
return OverrideResult::Warn;
}

break;
case FunctionEffect::Kind::Blocking:
case FunctionEffect::Kind::Allocating:
return OverrideResult::NoAction;
Expand Down
26 changes: 7 additions & 19 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,10 @@ static ResourceClass getResourceClass(RegisterType RT) {
return ResourceClass::Sampler;
case RegisterType::C:
case RegisterType::I:
llvm_unreachable("unexpected RegisterType value");
// Deliberately falling through to the unreachable below.
break;
}
llvm_unreachable("unexpected RegisterType value");
}

DeclBindingInfo *ResourceBindings::addDeclBindingInfo(const VarDecl *VD,
Expand Down Expand Up @@ -1039,21 +1041,6 @@ SemaHLSL::TakeLocForHLSLAttribute(const HLSLAttributedResourceType *RT) {
return LocInfo;
}

// Returns handle type of a resource, if the type is a resource
static const HLSLAttributedResourceType *
findHandleTypeOnResource(const Type *Ty) {
// If Ty is a resource class, the first field must
// be the resource handle of type HLSLAttributedResourceType
if (RecordDecl *RD = Ty->getAsCXXRecordDecl()) {
if (!RD->fields().empty()) {
const auto &FirstFD = RD->fields().begin();
return dyn_cast<HLSLAttributedResourceType>(
FirstFD->getType().getTypePtr());
}
}
return nullptr;
}

// Walks though the global variable declaration, collects all resource binding
// requirements and adds them to Bindings
void SemaHLSL::collectResourcesOnUserRecordDecl(const VarDecl *VD,
Expand All @@ -1075,7 +1062,7 @@ void SemaHLSL::collectResourcesOnUserRecordDecl(const VarDecl *VD,
continue;

if (const HLSLAttributedResourceType *AttrResType =
findHandleTypeOnResource(Ty)) {
HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
// Add a new DeclBindingInfo to Bindings if it does not already exist
ResourceClass RC = AttrResType->getAttrs().ResourceClass;
DeclBindingInfo *DBI = Bindings.getDeclBindingInfo(VD, RC);
Expand Down Expand Up @@ -1126,7 +1113,8 @@ static bool DiagnoseLocalRegisterBinding(Sema &S, SourceLocation &ArgLoc,

// Resource
if (const HLSLAttributedResourceType *AttrResType =
findHandleTypeOnResource(VD->getType().getTypePtr())) {
HLSLAttributedResourceType::findHandleTypeOnResource(
VD->getType().getTypePtr())) {
if (RegType == getRegisterType(AttrResType->getAttrs().ResourceClass))
return true;

Expand Down Expand Up @@ -2369,7 +2357,7 @@ void SemaHLSL::collectResourcesOnVarDecl(VarDecl *VD) {

// Resource (or array of resources)
if (const HLSLAttributedResourceType *AttrResType =
findHandleTypeOnResource(Ty)) {
HLSLAttributedResourceType::findHandleTypeOnResource(Ty)) {
Bindings.addDeclBindingInfo(VD, AttrResType->getAttrs().ResourceClass);
return;
}
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/Sema/SemaRISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ struct RVVIntrinsicDef {

struct RVVOverloadIntrinsicDef {
// Indexes of RISCVIntrinsicManagerImpl::IntrinsicList.
SmallVector<uint16_t, 8> Indexes;
SmallVector<uint32_t, 8> Indexes;
};

} // namespace
Expand Down Expand Up @@ -169,7 +169,7 @@ class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
// List of all RVV intrinsic.
std::vector<RVVIntrinsicDef> IntrinsicList;
// Mapping function name to index of IntrinsicList.
StringMap<uint16_t> Intrinsics;
StringMap<uint32_t> Intrinsics;
// Mapping function name to RVVOverloadIntrinsicDef.
StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics;

Expand Down Expand Up @@ -399,7 +399,7 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
Record.HasFRMRoundModeOp);

// Put into IntrinsicList.
uint16_t Index = IntrinsicList.size();
uint32_t Index = IntrinsicList.size();
assert(IntrinsicList.size() == (size_t)Index &&
"Intrinsics indices overflow.");
IntrinsicList.push_back({BuiltinName, Signature});
Expand Down Expand Up @@ -623,7 +623,12 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI,
ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(
TheCall->getType()->castAs<BuiltinType>());

if (Context.getTypeSize(Info.ElementType) == 64 && !TI.hasFeature("v"))
const FunctionDecl *FD = SemaRef.getCurFunctionDecl();
llvm::StringMap<bool> FunctionFeatureMap;
Context.getFunctionFeatureMap(FunctionFeatureMap, FD);

if (Context.getTypeSize(Info.ElementType) == 64 && !TI.hasFeature("v") &&
!FunctionFeatureMap.lookup("v"))
return Diag(TheCall->getBeginLoc(),
diag::err_riscv_builtin_requires_extension)
<< /* IsExtension */ true << TheCall->getSourceRange() << "v";
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -806,8 +806,7 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {

// Check to see if we're low on stack space. We can't do anything about this
// from here, but we can at least warn the user.
if (isStackNearlyExhausted())
warnStackExhausted(Ctx.PointOfInstantiation);
StackHandler.warnOnStackNearlyExhausted(Ctx.PointOfInstantiation);
}

void Sema::popCodeSynthesisContext() {
Expand Down
21 changes: 10 additions & 11 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManagerInternals.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TokenKinds.h"
Expand Down Expand Up @@ -9648,18 +9649,15 @@ DiagnosticBuilder ASTReader::Diag(SourceLocation Loc, unsigned DiagID) const {
return Diags.Report(Loc, DiagID);
}

void ASTReader::warnStackExhausted(SourceLocation Loc) {
void ASTReader::runWithSufficientStackSpace(SourceLocation Loc,
llvm::function_ref<void()> Fn) {
// When Sema is available, avoid duplicate errors.
if (SemaObj) {
SemaObj->warnStackExhausted(Loc);
SemaObj->runWithSufficientStackSpace(Loc, Fn);
return;
}

if (WarnedStackExhausted)
return;
WarnedStackExhausted = true;

Diag(Loc, diag::warn_stack_exhausted);
StackHandler.runWithSufficientStackSpace(Loc, Fn);
}

/// Retrieve the identifier table associated with the
Expand Down Expand Up @@ -10509,13 +10507,14 @@ ASTReader::ASTReader(Preprocessor &PP, InMemoryModuleCache &ModuleCache,
bool AllowConfigurationMismatch, bool ValidateSystemInputs,
bool ValidateASTInputFilesContent, bool UseGlobalIndex,
std::unique_ptr<llvm::Timer> ReadTimer)
: Listener(bool(DisableValidationKind &DisableValidationForModuleKind::PCH)
: Listener(bool(DisableValidationKind & DisableValidationForModuleKind::PCH)
? cast<ASTReaderListener>(new SimpleASTReaderListener(PP))
: cast<ASTReaderListener>(new PCHValidator(PP, *this))),
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()), PP(PP),
ContextObj(Context), ModuleMgr(PP.getFileManager(), ModuleCache,
PCHContainerRdr, PP.getHeaderSearchInfo()),
PCHContainerRdr(PCHContainerRdr), Diags(PP.getDiagnostics()),
StackHandler(Diags), PP(PP), ContextObj(Context),
ModuleMgr(PP.getFileManager(), ModuleCache, PCHContainerRdr,
PP.getHeaderSearchInfo()),
DummyIdResolver(PP), ReadTimer(std::move(ReadTimer)), isysroot(isysroot),
DisableValidationKind(DisableValidationKind),
AllowASTWithCompilerErrors(AllowASTWithCompilerErrors),
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4168,8 +4168,7 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
D->setDeclContext(Context.getTranslationUnitDecl());

// Reading some declarations can result in deep recursion.
clang::runWithSufficientStackSpace([&] { warnStackExhausted(DeclLoc); },
[&] { Reader.Visit(D); });
runWithSufficientStackSpace(DeclLoc, [&] { Reader.Visit(D); });

// If this declaration is also a declaration context, get the
// offsets for its tables of lexical and visible declarations.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ BugReportPtr BitwiseShiftValidator::checkOvershift() {
RightOpStr = formatv(" '{0}'", ConcreteRight->getValue());
else {
SValBuilder &SVB = Ctx.getSValBuilder();
if (const llvm::APSInt *MinRight = SVB.getMinValue(FoldedState, Right)) {
if (const llvm::APSInt *MinRight = SVB.getMinValue(FoldedState, Right);
MinRight && *MinRight >= LHSBitWidth) {
LowerBoundStr = formatv(" >= {0},", MinRight->getExtValue());
}
}
Expand Down
58 changes: 22 additions & 36 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,29 @@ class TrivialFunctionAnalysisVisitor
return true;
}

template <typename CheckFunction>
bool WithCachedResult(const Stmt *S, CheckFunction Function) {
// If the statement isn't in the cache, conservatively assume that
// it's not trivial until analysis completes. Insert false to the cache
// first to avoid infinite recursion.
auto [It, IsNew] = Cache.insert(std::make_pair(S, false));
template <typename StmtOrDecl, typename CheckFunction>
bool WithCachedResult(const StmtOrDecl *S, CheckFunction Function) {
auto CacheIt = Cache.find(S);
if (CacheIt != Cache.end())
return CacheIt->second;

// Treat a recursive statement to be trivial until proven otherwise.
auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(S, true));
if (!IsNew)
return It->second;
return RecursiveIt->second;

bool Result = Function();

if (!Result) {
for (auto &It : RecursiveFn)
It.second = false;
}
RecursiveIt = RecursiveFn.find(S);
assert(RecursiveIt != RecursiveFn.end());
Result = RecursiveIt->second;
RecursiveFn.erase(RecursiveIt);
Cache[S] = Result;

return Result;
}

Expand All @@ -292,16 +305,7 @@ class TrivialFunctionAnalysisVisitor
TrivialFunctionAnalysisVisitor(CacheTy &Cache) : Cache(Cache) {}

bool IsFunctionTrivial(const Decl *D) {
auto CacheIt = Cache.find(D);
if (CacheIt != Cache.end())
return CacheIt->second;

// Treat a recursive function call to be trivial until proven otherwise.
auto [RecursiveIt, IsNew] = RecursiveFn.insert(std::make_pair(D, true));
if (!IsNew)
return RecursiveIt->second;

bool Result = [&]() {
return WithCachedResult(D, [&]() {
if (auto *CtorDecl = dyn_cast<CXXConstructorDecl>(D)) {
for (auto *CtorInit : CtorDecl->inits()) {
if (!Visit(CtorInit->getInit()))
Expand All @@ -312,20 +316,7 @@ class TrivialFunctionAnalysisVisitor
if (!Body)
return false;
return Visit(Body);
}();

if (!Result) {
// D and its mutually recursive callers are all non-trivial.
for (auto &It : RecursiveFn)
It.second = false;
}
RecursiveIt = RecursiveFn.find(D);
assert(RecursiveIt != RecursiveFn.end());
Result = RecursiveIt->second;
RecursiveFn.erase(RecursiveIt);
Cache[D] = Result;

return Result;
});
}

bool VisitStmt(const Stmt *S) {
Expand Down Expand Up @@ -586,11 +577,6 @@ bool TrivialFunctionAnalysis::isTrivialImpl(

bool TrivialFunctionAnalysis::isTrivialImpl(
const Stmt *S, TrivialFunctionAnalysis::CacheTy &Cache) {
// If the statement isn't in the cache, conservatively assume that
// it's not trivial until analysis completes. Unlike a function case,
// we don't insert an entry into the cache until Visit returns
// since Visit* functions themselves make use of the cache.

TrivialFunctionAnalysisVisitor V(Cache);
bool Result = V.Visit(S);
assert(Cache.contains(S) && "Top-level statement not properly cached!");
Expand Down
85 changes: 47 additions & 38 deletions clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,8 @@ class SymbolicRangeInferrer
// calculate the effective range set by intersecting the range set
// for A - B and the negated range set of B - A.
getRangeForNegatedSymSym(SSE),
// If commutative, we may have constaints for the commuted variant.
getRangeCommutativeSymSym(SSE),
// If Sym is a comparison expression (except <=>),
// find any other comparisons with the same operands.
// See function description.
Expand Down Expand Up @@ -1485,6 +1487,21 @@ class SymbolicRangeInferrer
Sym->getType());
}

std::optional<RangeSet> getRangeCommutativeSymSym(const SymSymExpr *SSE) {
auto Op = SSE->getOpcode();
bool IsCommutative = llvm::is_contained(
// ==, !=, |, &, +, *, ^
{BO_EQ, BO_NE, BO_Or, BO_And, BO_Add, BO_Mul, BO_Xor}, Op);
if (!IsCommutative)
return std::nullopt;

SymbolRef Commuted = State->getSymbolManager().getSymSymExpr(
SSE->getRHS(), Op, SSE->getLHS(), SSE->getType());
if (const RangeSet *Range = getConstraint(State, Commuted))
return *Range;
return std::nullopt;
}

// Returns ranges only for binary comparison operators (except <=>)
// when left and right operands are symbolic values.
// Finds any other comparisons with the same operands.
Expand Down Expand Up @@ -1936,30 +1953,27 @@ class RangeConstraintManager : public RangedConstraintManager {
const llvm::APSInt &To, const llvm::APSInt &Adjustment) override;

private:
RangeSet::Factory F;
mutable RangeSet::Factory F;

RangeSet getRange(ProgramStateRef State, SymbolRef Sym);
RangeSet getRange(ProgramStateRef State, EquivalenceClass Class);
RangeSet getRange(ProgramStateRef State, SymbolRef Sym) const;
ProgramStateRef setRange(ProgramStateRef State, SymbolRef Sym,
RangeSet Range);
ProgramStateRef setRange(ProgramStateRef State, EquivalenceClass Class,
RangeSet Range);

RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment);
const llvm::APSInt &Adjustment) const;
RangeSet getSymGTRange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment);
const llvm::APSInt &Adjustment) const;
RangeSet getSymLERange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment);
const llvm::APSInt &Adjustment) const;
RangeSet getSymLERange(llvm::function_ref<RangeSet()> RS,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment);
const llvm::APSInt &Adjustment) const;
RangeSet getSymGERange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment);
const llvm::APSInt &Adjustment) const;
};

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2866,24 +2880,19 @@ ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,

const llvm::APSInt *RangeConstraintManager::getSymVal(ProgramStateRef St,
SymbolRef Sym) const {
const RangeSet *T = getConstraint(St, Sym);
return T ? T->getConcreteValue() : nullptr;
return getRange(St, Sym).getConcreteValue();
}

const llvm::APSInt *RangeConstraintManager::getSymMinVal(ProgramStateRef St,
SymbolRef Sym) const {
const RangeSet *T = getConstraint(St, Sym);
if (!T || T->isEmpty())
return nullptr;
return &T->getMinValue();
RangeSet Range = getRange(St, Sym);
return Range.isEmpty() ? nullptr : &Range.getMinValue();
}

const llvm::APSInt *RangeConstraintManager::getSymMaxVal(ProgramStateRef St,
SymbolRef Sym) const {
const RangeSet *T = getConstraint(St, Sym);
if (!T || T->isEmpty())
return nullptr;
return &T->getMaxValue();
RangeSet Range = getRange(St, Sym);
return Range.isEmpty() ? nullptr : &Range.getMaxValue();
}

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -3027,7 +3036,7 @@ RangeConstraintManager::removeDeadBindings(ProgramStateRef State,
}

RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
SymbolRef Sym) {
SymbolRef Sym) const {
return SymbolicRangeInferrer::inferRange(F, State, Sym);
}

Expand Down Expand Up @@ -3082,10 +3091,10 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
return setRange(St, Sym, New);
}

RangeSet RangeConstraintManager::getSymLTRange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) {
RangeSet
RangeConstraintManager::getSymLTRange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) const {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
switch (AdjustmentType.testInRange(Int, true)) {
Expand Down Expand Up @@ -3119,10 +3128,10 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
return setRange(St, Sym, New);
}

RangeSet RangeConstraintManager::getSymGTRange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) {
RangeSet
RangeConstraintManager::getSymGTRange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) const {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
switch (AdjustmentType.testInRange(Int, true)) {
Expand Down Expand Up @@ -3156,10 +3165,10 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
return setRange(St, Sym, New);
}

RangeSet RangeConstraintManager::getSymGERange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) {
RangeSet
RangeConstraintManager::getSymGERange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) const {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
switch (AdjustmentType.testInRange(Int, true)) {
Expand Down Expand Up @@ -3196,7 +3205,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
RangeSet
RangeConstraintManager::getSymLERange(llvm::function_ref<RangeSet()> RS,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) {
const llvm::APSInt &Adjustment) const {
// Before we do any real work, see if the value can even show up.
APSIntType AdjustmentType(Adjustment);
switch (AdjustmentType.testInRange(Int, true)) {
Expand All @@ -3222,10 +3231,10 @@ RangeConstraintManager::getSymLERange(llvm::function_ref<RangeSet()> RS,
return F.intersect(Default, Lower, Upper);
}

RangeSet RangeConstraintManager::getSymLERange(ProgramStateRef St,
SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) {
RangeSet
RangeConstraintManager::getSymLERange(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) const {
return getSymLERange([&] { return getRange(St, Sym); }, Int, Adjustment);
}

Expand Down
4 changes: 0 additions & 4 deletions clang/test/.gitattributes

This file was deleted.

14 changes: 14 additions & 0 deletions clang/test/AST/ByteCode/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,20 @@ namespace fpclassify {
char classify_subnorm [__builtin_fpclassify(-1, -1, -1, +1, -1, 1.0e-38f)];
}

namespace abs {
static_assert(__builtin_abs(14) == 14, "");
static_assert(__builtin_labs(14L) == 14L, "");
static_assert(__builtin_llabs(14LL) == 14LL, "");
static_assert(__builtin_abs(-14) == 14, "");
static_assert(__builtin_labs(-0x14L) == 0x14L, "");
static_assert(__builtin_llabs(-0x141414141414LL) == 0x141414141414LL, "");
#define BITSIZE(x) (sizeof(x) * 8)
constexpr int abs4 = __builtin_abs(1 << (BITSIZE(int) - 1)); // both-error {{must be initialized by a constant expression}}
constexpr long abs6 = __builtin_labs(1L << (BITSIZE(long) - 1)); // both-error {{must be initialized by a constant expression}}
constexpr long long abs8 = __builtin_llabs(1LL << (BITSIZE(long long) - 1)); // both-error {{must be initialized by a constant expression}}
#undef BITSIZE
} // namespace abs

namespace fabs {
static_assert(__builtin_fabs(-14.0) == 14.0, "");
}
Expand Down
22 changes: 22 additions & 0 deletions clang/test/AST/ByteCode/new-delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,28 @@ static_assert(virt_delete(false)); // both-error {{not an integral constant expr
// both-note {{in call to}}


namespace ToplevelScopeInTemplateArg {
class string {
public:
char *mem;
constexpr string() {
this->mem = new char(1);
}
constexpr ~string() {
delete this->mem;
}
constexpr unsigned size() const { return 4; }
};


template <unsigned N>
void test() {};

void f() {
test<string().size()>();
static_assert(string().size() == 4);
}
}

#else
/// Make sure we reject this prior to C++20
Expand Down
24 changes: 24 additions & 0 deletions clang/test/AST/ByteCode/placement-new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,27 @@ namespace UsedToCrash {
}
int alloc1 = (alloc(), 0);
}

constexpr bool change_union_member() {
union U {
int a;
int b;
};
U u = {.a = 1};
std::construct_at<int>(&u.b, 2);
return u.b == 2;
}
static_assert(change_union_member());

namespace PR48606 {
struct A { mutable int n = 0; };

constexpr bool f() {
A a;
A *p = &a;
p->~A();
std::construct_at<A>(p);
return true;
}
static_assert(f());
}
128 changes: 64 additions & 64 deletions clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY %s | FileCheck -check-prefix=EMPTY %s
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s


// This test tests two different AST generations. The "EMPTY" test mode verifies
// the AST generated by forward declaration of the HLSL types which happens on
// initializing the HLSL external AST with an AST Context.

// The non-empty mode has a use that requires the StructuredBuffer type be complete,
// which results in the AST being populated by the external AST source. That
// case covers the full implementation of the template declaration and the
// instantiated specialization.

// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class StructuredBuffer
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final

// There should be no more occurrances of StructuredBuffer
// EMPTY-NOT: StructuredBuffer

#ifndef EMPTY

StructuredBuffer<float> Buffer;

#endif

// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class StructuredBuffer definition

// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const StructuredBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'StructuredBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class StructuredBuffer definition

// CHECK: TemplateArgument type 'float'
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float'
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump -DEMPTY %s | FileCheck -check-prefix=EMPTY %s
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -ast-dump %s | FileCheck %s
// This test tests two different AST generations. The "EMPTY" test mode verifies
// the AST generated by forward declaration of the HLSL types which happens on
// initializing the HLSL external AST with an AST Context.
// The non-empty mode has a use that requires the StructuredBuffer type be complete,
// which results in the AST being populated by the external AST source. That
// case covers the full implementation of the template declaration and the
// instantiated specialization.
// EMPTY: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
// EMPTY-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// EMPTY-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit <undeserialized declarations> class StructuredBuffer
// EMPTY-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
// There should be no more occurrances of StructuredBuffer
// EMPTY-NOT: StructuredBuffer
#ifndef EMPTY
StructuredBuffer<float> Buffer;
#endif
// CHECK: ClassTemplateDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit StructuredBuffer
// CHECK-NEXT: TemplateTypeParmDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class depth 0 index 0 element_type
// CHECK-NEXT: CXXRecordDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit class StructuredBuffer definition
// CHECK: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const StructuredBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'StructuredBuffer<element_type>' lvalue implicit this
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline
// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class StructuredBuffer definition
// CHECK: TemplateArgument type 'float'
// CHECK-NEXT: BuiltinType 0x{{[0-9A-Fa-f]+}} 'float'
// CHECK-NEXT: FinalAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit final
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
39 changes: 39 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,42 @@ void foo() {
}

} // namespace local_assignment_to_global

namespace local_var_in_recursive_function {

struct TreeNode {
Ref<TreeNode> create() { return Ref(*new TreeNode); }

void ref() const { ++refCount; }
void deref() const {
if (!--refCount)
delete this;
}

int recursiveCost();
int recursiveWeight();
int weight();

int cost { 0 };
mutable unsigned refCount { 0 };
TreeNode* nextSibling { nullptr };
TreeNode* firstChild { nullptr };
};

int TreeNode::recursiveCost() {
// no warnings
unsigned totalCost = cost;
for (TreeNode* node = firstChild; node; node = node->nextSibling)
totalCost += recursiveCost();
return totalCost;
}

int TreeNode::recursiveWeight() {
unsigned totalCost = weight();
for (TreeNode* node = firstChild; node; node = node->nextSibling)
// expected-warning@-1{{Local variable 'node' is uncounted and unsafe [alpha.webkit.UncountedLocalVarsChecker]}}
totalCost += recursiveWeight();
return totalCost;
}

} // namespace local_var_in_recursive_function
12 changes: 12 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,15 @@ class RefCounted {
void mutuallyRecursive8() { mutuallyRecursive9(); someFunction(); }
void mutuallyRecursive9() { mutuallyRecursive8(); }

int recursiveCost() {
unsigned totalCost = 0;
for (unsigned i = 0; i < sizeof(children)/sizeof(*children); ++i) {
if (auto* child = children[i])
totalCost += child->recursiveCost();
}
return totalCost;
}

int trivial1() { return 123; }
float trivial2() { return 0.3; }
float trivial3() { return (float)0.4; }
Expand Down Expand Up @@ -448,6 +457,7 @@ class RefCounted {
Number* number { nullptr };
ComplexNumber complex;
Enum enumValue { Enum::Value1 };
RefCounted* children[4];
};

unsigned RefCounted::s_v = 0;
Expand Down Expand Up @@ -558,6 +568,8 @@ class UnrelatedClass {
getFieldTrivial().mutuallyRecursive9();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}

getFieldTrivial().recursiveCost(); // no-warning

getFieldTrivial().someFunction();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
getFieldTrivial().nonTrivial1();
Expand Down
Loading