29 changes: 14 additions & 15 deletions clang/bindings/python/tests/cindex/test_cursor.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import os
from clang.cindex import Config

from clang.cindex import (
AvailabilityKind,
BinaryOperator,
Config,
CursorKind,
StorageClass,
TemplateArgumentKind,
TranslationUnit,
TypeKind,
)

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

import ctypes
import gc
import unittest

from clang.cindex import AvailabilityKind
from clang.cindex import CursorKind
from clang.cindex import TemplateArgumentKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
from clang.cindex import BinaryOperator
from clang.cindex import StorageClass
from .util import get_cursor
from .util import get_cursors
from .util import get_tu

from .util import get_cursor, get_cursors, get_tu

kInput = """\
struct s0 {
Expand Down Expand Up @@ -170,7 +169,7 @@ def test_references(self):
self.assertIsInstance(cursor.translation_unit, TranslationUnit)

# If the TU was destroyed, this should cause a segfault.
parent = cursor.semantic_parent
cursor.semantic_parent

def test_canonical(self):
source = "struct X; struct X; struct X { int member; };"
Expand Down Expand Up @@ -344,7 +343,7 @@ class Bar {
)

self.assertEqual(len(copy_assignment_operators_cursors), 10)
self.assertTrue(len(non_copy_assignment_operators_cursors), 9)
self.assertEqual(len(non_copy_assignment_operators_cursors), 7)

self.assertTrue(
all(
Expand Down
5 changes: 2 additions & 3 deletions clang/bindings/python/tests/cindex/test_cursor_kind.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import os
from clang.cindex import Config

from clang.cindex import Config, CursorKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import CursorKind

import unittest


Expand Down
7 changes: 3 additions & 4 deletions clang/bindings/python/tests/cindex/test_diagnostics.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import os
from clang.cindex import Config

from clang.cindex import Config, Diagnostic

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import *
from .util import get_tu

import unittest

from .util import get_tu

# FIXME: We need support for invalid translation units to test better.

Expand Down
16 changes: 8 additions & 8 deletions clang/bindings/python/tests/cindex/test_enums.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import unittest

from clang.cindex import (
TokenKind,
AccessSpecifier,
AvailabilityKind,
BinaryOperator,
CursorKind,
TemplateArgumentKind,
ExceptionSpecificationKind,
AvailabilityKind,
AccessSpecifier,
TypeKind,
RefQualifierKind,
LinkageKind,
TLSKind,
RefQualifierKind,
StorageClass,
BinaryOperator,
TemplateArgumentKind,
TLSKind,
TokenKind,
TypeKind,
)


Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import os
from clang.cindex import Config

from clang.cindex import Config, CursorKind, ExceptionSpecificationKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

import clang.cindex
from clang.cindex import ExceptionSpecificationKind
from .util import get_tu

import unittest

from .util import get_tu


def find_function_declarations(node, declarations=[]):
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
if node.kind == CursorKind.FUNCTION_DECL:
declarations.append(node)
for child in node.get_children():
declarations = find_function_declarations(child, declarations)
Expand Down
5 changes: 2 additions & 3 deletions clang/bindings/python/tests/cindex/test_file.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import os
from clang.cindex import Config

from clang.cindex import Config, File, Index

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import Index, File

import unittest


Expand Down
8 changes: 3 additions & 5 deletions clang/bindings/python/tests/cindex/test_index.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import os
from clang.cindex import Config

from clang.cindex import Config, Index, TranslationUnit

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import *
import os
import unittest


kInputsDir = os.path.join(os.path.dirname(__file__), "INPUTS")


class TestIndex(unittest.TestCase):
def test_create(self):
index = Index.create()
Index.create()

# FIXME: test Index.read

Expand Down
12 changes: 4 additions & 8 deletions clang/bindings/python/tests/cindex/test_linkage.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import os
from clang.cindex import Config

from clang.cindex import Config, LinkageKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import LinkageKind
from clang.cindex import Cursor
from clang.cindex import TranslationUnit

from .util import get_cursor
from .util import get_tu

import unittest

from .util import get_cursor, get_tu


class TestLinkage(unittest.TestCase):
def test_linkage(self):
Expand Down
19 changes: 10 additions & 9 deletions clang/bindings/python/tests/cindex/test_location.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import os
from clang.cindex import Config

from clang.cindex import (
Config,
Cursor,
File,
SourceLocation,
SourceRange,
TranslationUnit,
)

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import Cursor
from clang.cindex import File
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu

import unittest

from .util import get_cursor, get_tu

baseInput = "int one;\nint two;\n"

Expand Down
10 changes: 2 additions & 8 deletions clang/bindings/python/tests/cindex/test_rewrite.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import unittest
import tempfile
import unittest

from clang.cindex import (
Rewriter,
TranslationUnit,
File,
SourceLocation,
SourceRange,
)
from clang.cindex import File, Rewriter, SourceLocation, SourceRange, TranslationUnit


class TestRewrite(unittest.TestCase):
Expand Down
4 changes: 2 additions & 2 deletions clang/bindings/python/tests/cindex/test_source_range.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import os
from clang.cindex import Config

from clang.cindex import Config, SourceLocation, SourceRange, TranslationUnit

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

import unittest
from clang.cindex import SourceLocation, SourceRange, TranslationUnit

from .util import get_tu

Expand Down
12 changes: 4 additions & 8 deletions clang/bindings/python/tests/cindex/test_tls_kind.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import os
from clang.cindex import Config

from clang.cindex import Config, TLSKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import TLSKind
from clang.cindex import Cursor
from clang.cindex import TranslationUnit

from .util import get_cursor
from .util import get_tu

import unittest

from .util import get_cursor, get_tu


class TestTLSKind(unittest.TestCase):
def test_tls_kind(self):
Expand Down
5 changes: 2 additions & 3 deletions clang/bindings/python/tests/cindex/test_token_kind.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import os
from clang.cindex import Config

from clang.cindex import Config, TokenKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import TokenKind

import unittest


Expand Down
11 changes: 3 additions & 8 deletions clang/bindings/python/tests/cindex/test_tokens.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import os
from clang.cindex import Config

from clang.cindex import Config, CursorKind, SourceLocation, SourceRange, TokenKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from clang.cindex import CursorKind
from clang.cindex import Index
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from clang.cindex import TokenKind
import unittest

from .util import get_tu

import unittest


class TestTokens(unittest.TestCase):
def test_token_to_cursor(self):
Expand Down
58 changes: 25 additions & 33 deletions clang/bindings/python/tests/cindex/test_translation_unit.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
import os
from clang.cindex import Config

from clang.cindex import (
Config,
Cursor,
CursorKind,
File,
Index,
SourceLocation,
SourceRange,
TranslationUnit,
TranslationUnitLoadError,
TranslationUnitSaveError,
)

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

from contextlib import contextmanager
import gc
import os
import sys
import tempfile
import unittest
from contextlib import contextmanager
from pathlib import Path

from clang.cindex import CursorKind
from clang.cindex import Cursor
from clang.cindex import File
from clang.cindex import Index
from clang.cindex import SourceLocation
from clang.cindex import SourceRange
from clang.cindex import TranslationUnitSaveError
from clang.cindex import TranslationUnitLoadError
from clang.cindex import TranslationUnit
from .util import get_cursor
from .util import get_tu
from .util import skip_if_no_fspath
from .util import str_to_path

from .util import get_cursor, get_tu

kInputsDir = os.path.join(os.path.dirname(__file__), "INPUTS")

Expand All @@ -47,7 +45,7 @@ def save_tu_pathlike(tu):
Returns the filename it was saved to.
"""
with tempfile.NamedTemporaryFile() as t:
tu.save(str_to_path(t.name))
tu.save(Path(t.name))
yield t.name


Expand Down Expand Up @@ -105,32 +103,29 @@ def test_unsaved_files(self):
self.assertEqual(spellings[-1], "y")

def test_unsaved_files_2(self):
if sys.version_info.major >= 3:
from io import StringIO
else:
from io import BytesIO as StringIO
from io import StringIO

tu = TranslationUnit.from_source(
"fake.c", unsaved_files=[("fake.c", StringIO("int x;"))]
)
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-1], "x")

@skip_if_no_fspath
def test_from_source_accepts_pathlike(self):
tu = TranslationUnit.from_source(
str_to_path("fake.c"),
Path("fake.c"),
["-Iincludes"],
unsaved_files=[
(
str_to_path("fake.c"),
Path("fake.c"),
"""
#include "fake.h"
int x;
int SOME_DEFINE;
""",
),
(
str_to_path("includes/fake.h"),
Path("includes/fake.h"),
"""
#define SOME_DEFINE y
""",
Expand Down Expand Up @@ -192,7 +187,6 @@ def test_save(self):
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)

@skip_if_no_fspath
def test_save_pathlike(self):
"""Ensure TranslationUnit.save() works with PathLike filename."""

Expand Down Expand Up @@ -234,14 +228,13 @@ def test_load(self):
# Just in case there is an open file descriptor somewhere.
del tu2

@skip_if_no_fspath
def test_load_pathlike(self):
"""Ensure TranslationUnits can be constructed from saved files -
PathLike variant."""
tu = get_tu("int foo();")
self.assertEqual(len(tu.diagnostics), 0)
with save_tu(tu) as path:
tu2 = TranslationUnit.from_ast_file(filename=str_to_path(path))
tu2 = TranslationUnit.from_ast_file(filename=Path(path))
self.assertEqual(len(tu2.diagnostics), 0)

foo = get_cursor(tu2, "foo")
Expand All @@ -268,18 +261,17 @@ def test_get_file(self):
with self.assertRaises(Exception):
f = tu.get_file("foobar.cpp")

@skip_if_no_fspath
def test_get_file_pathlike(self):
"""Ensure tu.get_file() works appropriately with PathLike filenames."""

tu = get_tu("int foo();")

f = tu.get_file(str_to_path("t.c"))
f = tu.get_file(Path("t.c"))
self.assertIsInstance(f, File)
self.assertEqual(f.name, "t.c")

with self.assertRaises(Exception):
f = tu.get_file(str_to_path("foobar.cpp"))
f = tu.get_file(Path("foobar.cpp"))

def test_get_source_location(self):
"""Ensure tu.get_source_location() works."""
Expand Down
18 changes: 6 additions & 12 deletions clang/bindings/python/tests/cindex/test_type.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import os
from clang.cindex import Config

from clang.cindex import Config, CursorKind, RefQualifierKind, TranslationUnit, TypeKind

if "CLANG_LIBRARY_PATH" in os.environ:
Config.set_library_path(os.environ["CLANG_LIBRARY_PATH"])

import gc
import unittest

from clang.cindex import CursorKind
from clang.cindex import TranslationUnit
from clang.cindex import TypeKind
from clang.cindex import RefQualifierKind
from .util import get_cursor
from .util import get_cursors
from .util import get_tu

from .util import get_cursor, get_cursors, get_tu

kInput = """\
Expand Down Expand Up @@ -138,7 +132,7 @@ def test_references(self):
self.assertIsInstance(t.translation_unit, TranslationUnit)

# If the TU was destroyed, this should cause a segfault.
decl = t.get_declaration()
t.get_declaration()

def testConstantArray(self):
tu = get_tu(constarrayInput)
Expand Down Expand Up @@ -459,8 +453,8 @@ def test_offset(self):
(["-target", "i386-pc-win32"], (8, 16, 0, 32, 64, 96)),
(["-target", "msp430-none-none"], (2, 14, 0, 32, 64, 96)),
]
for flags, values in tries:
align, total, f1, bariton, foo, bar = values
for _, values in tries:
_, _, f1, bariton, foo, bar = values
tu = get_tu(source)
teststruct = get_cursor(tu, "Test")
children = list(teststruct.get_children())
Expand Down
20 changes: 1 addition & 19 deletions clang/bindings/python/tests/cindex/util.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
# This file provides common utility functions for the test suite.

import os

HAS_FSPATH = hasattr(os, "fspath")

if HAS_FSPATH:
from pathlib import Path as str_to_path
else:
str_to_path = None

import unittest

from clang.cindex import Cursor
from clang.cindex import TranslationUnit
from clang.cindex import Cursor, TranslationUnit


def get_tu(source, lang="c", all_warnings=False, flags=[]):
Expand Down Expand Up @@ -81,14 +69,8 @@ def get_cursors(source, spelling):
return cursors


skip_if_no_fspath = unittest.skipUnless(
HAS_FSPATH, "Requires file system path protocol / Python 3.6+"
)

__all__ = [
"get_cursor",
"get_cursors",
"get_tu",
"skip_if_no_fspath",
"str_to_path",
]
5 changes: 0 additions & 5 deletions clang/docs/ClangFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -363,8 +363,3 @@ those as well).

These commands use the file paths shown in the diff output
so they will only work from the root of the repository.

Current State of Clang Format for LLVM
======================================

The following table :doc:`ClangFormattedStatus` shows the current status of clang-formatting for the entire LLVM source tree.
8,536 changes: 0 additions & 8,536 deletions clang/docs/ClangFormattedStatus.rst

This file was deleted.

3 changes: 0 additions & 3 deletions clang/docs/ClangLinkerWrapper.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,11 @@ only for the linker wrapper will be forwarded to the wrapped linker job.
USAGE: clang-linker-wrapper [options] -- <options to passed to the linker>
OPTIONS:
--bitcode-library=<kind>-<triple>-<arch>=<path>
Extra bitcode library to link
--cuda-path=<dir> Set the system CUDA path
--device-debug Use debugging
--device-linker=<value> or <triple>=<value>
Arguments to pass to the device linker invocation
--dry-run Print program arguments without running
--embed-bitcode Embed linked bitcode in the module
--help-hidden Display all available options
--help Display available options (--help-hidden for more)
--host-triple=<triple> Triple to use for the host compilation
Expand Down
82 changes: 82 additions & 0 deletions clang/docs/ClangSYCLLinker.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
=======================
Clang SYCL Linker
=======================

.. contents::
:local:

.. _clang-sycl-linker:

Introduction
============

This tool works as a wrapper around the SYCL device code linking process.
The purpose of this tool is to provide an interface to link SYCL device bitcode
in LLVM IR format, SYCL device bitcode in SPIR-V IR format, and native binary
objects, and then use the SPIR-V LLVM Translator tool on fully linked device
objects to produce the final output.
After the linking stage, the fully linked device code in LLVM IR format may
undergo several SYCL-specific finalization steps before the SPIR-V code
generation step.
The tool will also support the Ahead-Of-Time (AOT) compilation flow. AOT
compilation is the process of invoking the back-end at compile time to produce
the final binary, as opposed to just-in-time (JIT) compilation when final code
generation is deferred until application runtime.

Device code linking for SYCL offloading has several known quirks that
make it difficult to use in a unified offloading setting. Two of the primary
issues are:
1. Several finalization steps are required to be run on the fully linked LLVM
IR bitcode to guarantee conformance to SYCL standards. This step is unique to
the SYCL offloading compilation flow.
2. The SPIR-V LLVM Translator tool is an external tool and hence SPIR-V IR code
generation cannot be done as part of LTO. This limitation can be lifted once
the SPIR-V backend is available as a viable LLVM backend.

This tool has been proposed to work around these issues.

Usage
=====

This tool can be used with the following options. Several of these options will
be passed down to downstream tools like 'llvm-link', 'llvm-spirv', etc.

.. code-block:: console
OVERVIEW: A utility that wraps around the SYCL device code linking process.
This enables linking and code generation for SPIR-V JIT targets and AOT
targets.
USAGE: clang-sycl-linker [options]
OPTIONS:
--arch <value> Specify the name of the target architecture.
--dry-run Print generated commands without running.
-g Specify that this was a debug compile.
-help-hidden Display all available options
-help Display available options (--help-hidden for more)
--library-path=<dir> Set the library path for SYCL device libraries
--device-libs=<value> A comma separated list of device libraries that are linked during the device link
-o <path> Path to file to write output
--save-temps Save intermediate results
--triple <value> Specify the target triple.
--version Display the version number and exit
-v Print verbose information
-spirv-dump-device-code=<dir> Directory to dump SPIR-V IR code into
-is-windows-msvc-env Specify if we are compiling under windows environment
-llvm-spirv-options=<value> Pass options to llvm-spirv tool
--llvm-spirv-path=<dir> Set the system llvm-spirv path
Example
=======

This tool is intended to be invoked when targeting any of the target offloading
toolchains. When the --sycl-link option is passed to the clang driver, the
driver will invoke the linking job of the target offloading toolchain, which in
turn will invoke this tool. This tool can be used to create one or more fully
linked device images that are ready to be wrapped and linked with host code to
generate the final executable.

.. code-block:: console
clang-sycl-linker --triple spirv64 --arch native input.bc
13 changes: 9 additions & 4 deletions clang/docs/RealtimeSanitizer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ RealtimeSanitizer (a.k.a. RTSan) is a real-time safety testing tool for C and C+
projects. RTSan can be used to detect real-time violations, i.e. calls to methods
that are not safe for use in functions with deterministic run time requirements.
RTSan considers any function marked with the ``[[clang::nonblocking]]`` attribute
to be a real-time function. If RTSan detects a call to ``malloc``, ``free``,
``pthread_mutex_lock``, or anything else that could have a non-deterministic
execution time in a function marked ``[[clang::nonblocking]]``
RTSan raises an error.
to be a real-time function. At run-time, if RTSan detects a call to ``malloc``,
``free``, ``pthread_mutex_lock``, or anything else known to have a
non-deterministic execution time in a function marked ``[[clang::nonblocking]]``
it raises an error.

RTSan performs its analysis at run-time but shares the ``[[clang::nonblocking]]``
attribute with the :doc:`FunctionEffectAnalysis` system, which operates at
compile-time to detect potential real-time safety violations. For comprehensive
detection of real-time safety issues, it is recommended to use both systems together.

The runtime slowdown introduced by RealtimeSanitizer is negligible.

Expand Down
23 changes: 21 additions & 2 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ C++ Specific Potentially Breaking Changes
unsigned operator""_udl_name(unsigned long long);

- Clang will now produce an error diagnostic when [[clang::lifetimebound]] is
applied on a parameter of a function that returns void. This was previously
applied on a parameter of a function that returns void. This was previously
ignored and had no effect. (#GH107556)

.. code-block:: c++
Expand Down Expand Up @@ -338,6 +338,19 @@ Removed Compiler Flags
Attribute Changes in Clang
--------------------------

- The ``swift_attr`` can now be applied to types. To make it possible to use imported APIs
in Swift safely there has to be a way to annotate individual parameters and result types
with relevant attributes that indicate that e.g. a block is called on a particular actor
or it accepts a Sendable or global-actor (i.e. ``@MainActor``) isolated parameter.

For example:

.. code-block:: objc
@interface MyService
-(void) handle: (void (^ __attribute__((swift_attr("@Sendable"))))(id)) handler;
@end
- Clang now disallows more than one ``__attribute__((ownership_returns(class, idx)))`` with
different class names attached to one function.

Expand Down Expand Up @@ -469,7 +482,8 @@ Bug Fixes in This Version
- Fixed a crash using ``__array_rank`` on 64-bit targets. (#GH113044).
- The warning emitted for an unsupported register variable type now points to
the unsupported type instead of the ``register`` keyword (#GH109776).
- Fixed a crash when emit ctor for global variant with flexible array init (#GH113187).
- Fixed a crash when emit ctor for global variant with flexible array init (#GH113187).
- Fixed a crash when GNU statement expression contains invalid statement (#GH113468).

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -573,6 +587,8 @@ Bug Fixes to C++ Support
(#GH95854).
- Fixed an assertion failure when evaluating an invalid expression in an array initializer. (#GH112140)
- Fixed an assertion failure in range calculations for conditional throw expressions. (#GH111854)
- Clang now correctly ignores previous partial specializations of member templates explicitly specialized for
an implicitly instantiated class template specialization. (#GH51051)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -658,6 +674,7 @@ X86 Support

- Supported intrinsics for ``MOVRS AND AVX10.2``.
* Supported intrinsics of ``_mm(256|512)_(mask(z))_loadrs_epi(8|16|32|64)``.
- Support ISA of ``AMX-FP8``.

Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -742,6 +759,8 @@ AST Matchers

- Fixed a crash when traverse lambda expr with invalid captures. (#GH106444)

- Fixed ``isInstantiated`` and ``isInTemplateInstantiation`` to also match for variable templates. (#GH110666)

- Ensure ``hasName`` matches template specializations across inline namespaces,
making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent.

Expand Down
2 changes: 1 addition & 1 deletion clang/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ Using Clang Tools
ClangCheck
ClangFormat
ClangFormatStyleOptions
ClangFormattedStatus
ClangLinkerWrapper
ClangNVLinkWrapper
ClangOffloadBundler
ClangOffloadPackager
ClangRepl
ClangSYCLLinker

Design Documents
================
Expand Down
8,827 changes: 0 additions & 8,827 deletions clang/docs/tools/clang-formatted-files.txt

This file was deleted.

7 changes: 7 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1719,8 +1719,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;

QualType getAttributedType(attr::Kind attrKind, QualType modifiedType,
QualType equivalentType,
const Attr *attr = nullptr) const;

QualType getAttributedType(const Attr *attr, QualType modifiedType,
QualType equivalentType) const;

QualType getAttributedType(NullabilityKind nullability, QualType modifiedType,
QualType equivalentType);

QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
QualType Wrapped) const;

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def APValue : PropertyType { let PassByReference = 1; }
def APValueKind : EnumPropertyType<"APValue::ValueKind">;
def ArraySizeModifier : EnumPropertyType<"ArraySizeModifier">;
def AttrKind : EnumPropertyType<"attr::Kind">;
def Attr : PropertyType<"const Attr *">;
def AutoTypeKeyword : EnumPropertyType;
def Bool : PropertyType<"bool">;
def BuiltinTypeKind : EnumPropertyType<"BuiltinType::Kind">;
Expand Down
42 changes: 17 additions & 25 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class ValueDecl;
class TagDecl;
class TemplateParameterList;
class Type;
class Attr;

enum {
TypeAlignmentInBits = 4,
Expand Down Expand Up @@ -6130,21 +6131,29 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
private:
friend class ASTContext; // ASTContext creates these

const Attr *Attribute;

QualType ModifiedType;
QualType EquivalentType;

AttributedType(QualType canon, attr::Kind attrKind, QualType modified,
QualType equivalent)
: Type(Attributed, canon, equivalent->getDependence()),
ModifiedType(modified), EquivalentType(equivalent) {
AttributedTypeBits.AttrKind = attrKind;
}
: AttributedType(canon, attrKind, nullptr, modified, equivalent) {}

AttributedType(QualType canon, const Attr *attr, QualType modified,
QualType equivalent);

private:
AttributedType(QualType canon, attr::Kind attrKind, const Attr *attr,
QualType modified, QualType equivalent);

public:
Kind getAttrKind() const {
return static_cast<Kind>(AttributedTypeBits.AttrKind);
}

const Attr *getAttr() const { return Attribute; }

QualType getModifiedType() const { return ModifiedType; }
QualType getEquivalentType() const { return EquivalentType; }

Expand Down Expand Up @@ -6176,25 +6185,6 @@ class AttributedType : public Type, public llvm::FoldingSetNode {

std::optional<NullabilityKind> getImmediateNullability() const;

/// Retrieve the attribute kind corresponding to the given
/// nullability kind.
static Kind getNullabilityAttrKind(NullabilityKind kind) {
switch (kind) {
case NullabilityKind::NonNull:
return attr::TypeNonNull;

case NullabilityKind::Nullable:
return attr::TypeNullable;

case NullabilityKind::NullableResult:
return attr::TypeNullableResult;

case NullabilityKind::Unspecified:
return attr::TypeNullUnspecified;
}
llvm_unreachable("Unknown nullability kind.");
}

/// Strip off the top-level nullability annotation on the given
/// type, if it's there.
///
Expand All @@ -6207,14 +6197,16 @@ class AttributedType : public Type, public llvm::FoldingSetNode {
static std::optional<NullabilityKind> stripOuterNullability(QualType &T);

void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getAttrKind(), ModifiedType, EquivalentType);
Profile(ID, getAttrKind(), ModifiedType, EquivalentType, Attribute);
}

static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind,
QualType modified, QualType equivalent) {
QualType modified, QualType equivalent,
const Attr *attr) {
ID.AddInteger(attrKind);
ID.AddPointer(modified.getAsOpaquePtr());
ID.AddPointer(equivalent.getAsOpaquePtr());
ID.AddPointer(attr);
}

static bool classof(const Type *T) {
Expand Down
8 changes: 6 additions & 2 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -668,12 +668,16 @@ let Class = AttributedType in {
def : Property<"equivalentType", QualType> {
let Read = [{ node->getEquivalentType() }];
}
def : Property<"attribute", AttrKind> {
def : Property<"attrKind", AttrKind> {
let Read = [{ node->getAttrKind() }];
}
def : Property<"attribute", Attr> {
let Read = [{ node->getAttr() }];
}

def : Creator<[{
return ctx.getAttributedType(attribute, modifiedType, equivalentType);
return ctx.getAttributedType(attrKind, modifiedType,
equivalentType, attribute);
}]>;
}

Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -6750,7 +6750,8 @@ AST_POLYMORPHIC_MATCHER(isTemplateInstantiation,
/// matches 'A(int) {...};' and 'A(unsigned) {...}'.
AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) {
auto IsInstantiation = decl(anyOf(cxxRecordDecl(isTemplateInstantiation()),
functionDecl(isTemplateInstantiation())));
functionDecl(isTemplateInstantiation()),
varDecl(isTemplateInstantiation())));
return decl(anyOf(IsInstantiation, hasAncestor(IsInstantiation)));
}

Expand All @@ -6769,9 +6770,9 @@ AST_MATCHER_FUNCTION(internal::Matcher<Decl>, isInstantiated) {
/// will NOT match j += 42; as it's shared between the template definition and
/// instantiation.
AST_MATCHER_FUNCTION(internal::Matcher<Stmt>, isInTemplateInstantiation) {
return stmt(
hasAncestor(decl(anyOf(cxxRecordDecl(isTemplateInstantiation()),
functionDecl(isTemplateInstantiation())))));
return stmt(hasAncestor(decl(anyOf(cxxRecordDecl(isTemplateInstantiation()),
functionDecl(isTemplateInstantiation()),
varDecl(isTemplateInstantiation())))));
}

/// Matches explicit template specializations of function, class, or
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2838,7 +2838,7 @@ def SwiftAsyncName : InheritableAttr {
let Documentation = [SwiftAsyncNameDocs];
}

def SwiftAttr : InheritableAttr {
def SwiftAttr : DeclOrTypeAttr {
let Spellings = [GNU<"swift_attr">];
let Args = [StringArgument<"Attribute">];
let Documentation = [SwiftAttrDocs];
Expand Down
32 changes: 22 additions & 10 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3702,20 +3702,32 @@ user-declared functions. For example:

.. code-block:: c++

#include <map>
#include <string>

using namespace std::literals;

// Returns m[key] if key is present, or default_value if not.
template<typename T, typename U>
const U &get_or_default(const std::map<T, U> &m [[clang::lifetimebound]],
const T &key, /* note, not lifetimebound */
const U &default_value [[clang::lifetimebound]]);
const U &default_value [[clang::lifetimebound]]) {
if (auto iter = m.find(key); iter != m.end()) return iter->second;
else return default_value;
}

std::map<std::string, std::string> m;
// warning: temporary "bar"s that might be bound to local reference 'val'
// will be destroyed at the end of the full-expression
const std::string &val = get_or_default(m, "foo"s, "bar"s);
int main() {
std::map<std::string, std::string> m;
// warning: temporary bound to local reference 'val1' will be destroyed
// at the end of the full-expression
const std::string &val1 = get_or_default(m, "foo"s, "bar"s);

// No warning in this case.
std::string def_val = "bar"s;
const std::string &val = get_or_default(m, "foo"s, def_val);
// No warning in this case.
std::string def_val = "bar"s;
const std::string &val2 = get_or_default(m, "foo"s, def_val);

return 0;
}

The attribute can be applied to the implicit ``this`` parameter of a member
function by writing the attribute after the function type:
Expand Down Expand Up @@ -4495,8 +4507,8 @@ def SwiftAttrDocs : Documentation {
let Heading = "swift_attr";
let Content = [{
The ``swift_attr`` provides a Swift-specific annotation for the declaration
to which the attribute appertains to. It can be used on any declaration
in Clang. This kind of annotation is ignored by Clang as it doesn't have any
or type to which the attribute appertains to. It can be used on any declaration
or type in Clang. This kind of annotation is ignored by Clang as it doesn't have any
semantic meaning in languages supported by Clang. The Swift compiler can
interpret these annotations according to its own rules when importing C or
Objective-C declarations.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_bf8, "fUiUif", "nc", "dot11-insts")
//===----------------------------------------------------------------------===//
TARGET_BUILTIN(__builtin_amdgcn_permlane16, "UiUiUiUiUiIbIb", "nc", "gfx10-insts")
TARGET_BUILTIN(__builtin_amdgcn_permlanex16, "UiUiUiUiUiIbIb", "nc", "gfx10-insts")
TARGET_BUILTIN(__builtin_amdgcn_mov_dpp8, "UiUiIUi", "nc", "gfx10-insts")
TARGET_BUILTIN(__builtin_amdgcn_mov_dpp8, "UiUiIUi", "nct", "gfx10-insts")
TARGET_BUILTIN(__builtin_amdgcn_s_ttracedata_imm, "vIs", "n", "gfx10-insts")

//===----------------------------------------------------------------------===//
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/BuiltinsBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def ConstIgnoringExceptions : Attribute<"g">;
// This function requires a specific header or an explicit declaration.
def RequireDeclaration : Attribute<"h">;

// FIXME: Why is this not simply the min_vector_width attribute?
// Vector has to be at least N bits wide.
class RequiredVectorWidth<int N> : IndexedAttribute<"V", N>;

class PrintfFormat<int I> : IndexedAttribute<"p", I>;
class VPrintfFormat<int I> : IndexedAttribute<"P", I>;
class ScanfFormat<int I> : IndexedAttribute<"s", I>;
Expand Down
126 changes: 0 additions & 126 deletions clang/include/clang/Basic/BuiltinsX86.def
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,6 @@
# define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
#endif

// Undefined Values
//
TARGET_BUILTIN(__builtin_ia32_undef128, "V2d", "ncV:128:", "")
TARGET_BUILTIN(__builtin_ia32_undef256, "V4d", "ncV:256:", "")
TARGET_BUILTIN(__builtin_ia32_undef512, "V8d", "ncV:512:", "")

// FLAGS
//
TARGET_BUILTIN(__builtin_ia32_readeflags_u32, "Ui", "n", "")
TARGET_BUILTIN(__builtin_ia32_writeeflags_u32, "vUi", "n", "")

// MMX
//
// All MMX instructions will be generated via builtins. Any MMX vector
Expand All @@ -46,113 +35,8 @@ TARGET_BUILTIN(__builtin_ia32_writeeflags_u32, "vUi", "n", "")
// argument and our prior approach of using a #define to the current built-in
// doesn't work in the presence of re-declaration of _mm_prefetch for windows.
TARGET_BUILTIN(_mm_prefetch, "vcC*i", "nc", "mmx")
TARGET_BUILTIN(__builtin_ia32_emms, "v", "n", "mmx")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v4hi, "sV4sIi", "ncV:64:", "sse")
TARGET_BUILTIN(__builtin_ia32_vec_set_v4hi, "V4sV4ssIi", "ncV:64:", "sse")

// SSE intrinsics.
TARGET_BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_comile, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_comigt, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_comige, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_comineq, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_ucomieq, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_ucomilt, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_ucomile, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_ucomigt, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_ucomige, "iV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_ucomineq, "iV4fV4f", "ncV:128:", "sse")

TARGET_BUILTIN(__builtin_ia32_comisdeq, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_comisdlt, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_comisdle, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_comisdgt, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_comisdge, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_comisdneq, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_ucomisdeq, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_ucomisdlt, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "ncV:128:", "sse2")

TARGET_BUILTIN(__builtin_ia32_cmpeqps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpltps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpleps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpunordps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpneqps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpnltps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpnleps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpordps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpeqss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpltss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpless, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpunordss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpneqss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpnltss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpnless, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpordss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "ncV:128:", "sse")
TARGET_BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "ncV:128:", "sse")

TARGET_BUILTIN(__builtin_ia32_cmpeqpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpltpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmplepd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpunordpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpneqpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpnltpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpnlepd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpordpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpeqsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpltsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmplesd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpunordsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpneqsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpnltsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpnlesd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpordsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_packsswb128, "V16cV8sV8s", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_packssdw128, "V8sV4iV4i", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_packuswb128, "V16cV8sV8s", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v2di, "OiV2OiIi", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v4si, "iV4iIi", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v4sf, "fV4fIi", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_vec_ext_v8hi, "sV8sIi", "ncV:128:", "sse2")
TARGET_BUILTIN(__builtin_ia32_vec_set_v8hi, "V8sV8ssIi", "ncV:128:", "sse2")

TARGET_BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "ncV:128:", "sse3")
TARGET_BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "ncV:128:", "sse3")
TARGET_BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "ncV:128:", "sse3")
TARGET_BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "ncV:128:", "sse3")
TARGET_BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "ncV:128:", "sse3")
TARGET_BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "ncV:128:", "sse3")
TARGET_BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_pmaddubsw128, "V8sV16cV16c", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "ncV:128:", "ssse3")
TARGET_BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "ncV:128:", "ssse3")

TARGET_BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "n", "sse")
TARGET_HEADER_BUILTIN(_mm_setcsr, "vUi", "nh",XMMINTRIN_H, ALL_LANGUAGES, "sse")
Expand Down Expand Up @@ -316,16 +200,6 @@ TARGET_BUILTIN(__builtin_ia32_pclmulqdq256, "V4OiV4OiV4OiIc", "ncV:256:", "vpclm
TARGET_BUILTIN(__builtin_ia32_pclmulqdq512, "V8OiV8OiV8OiIc", "ncV:512:", "avx512f,evex512,vpclmulqdq")

// AVX
TARGET_BUILTIN(__builtin_ia32_addsubpd256, "V4dV4dV4d", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_addsubps256, "V8fV8fV8f", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_haddpd256, "V4dV4dV4d", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_hsubps256, "V8fV8fV8f", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_hsubpd256, "V4dV4dV4d", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_haddps256, "V8fV8fV8f", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_maxpd256, "V4dV4dV4d", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_maxps256, "V8fV8fV8f", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_minpd256, "V4dV4dV4d", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_minps256, "V8fV8fV8f", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_vpermilvarpd, "V2dV2dV2Oi", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_vpermilvarps, "V4fV4fV4i", "ncV:256:", "avx")
TARGET_BUILTIN(__builtin_ia32_vpermilvarpd256, "V4dV4dV4Oi", "ncV:256:", "avx")
Expand Down
137 changes: 137 additions & 0 deletions clang/include/clang/Basic/BuiltinsX86.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//===--- BuiltinsX86.td - X86 Builtin function database ---------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the X86-specific builtin function database.
//
//===----------------------------------------------------------------------===//

include "clang/Basic/BuiltinsBase.td"

class X86Builtin<string prototype> : TargetBuiltin {
let Spellings = ["__builtin_ia32_" # NAME];
let Prototype = prototype;
}

// Undefined Values
def undef128 : X86Builtin<"_Vector<2, double>()"> {
let Attributes = [Const, NoThrow, RequiredVectorWidth<128>];
}

def undef256 : X86Builtin<"_Vector<4, double>()"> {
let Attributes = [Const, NoThrow, RequiredVectorWidth<256>];
}

def undef512 : X86Builtin<"_Vector<8, double>()"> {
let Attributes = [Const, NoThrow, RequiredVectorWidth<512>];
}

// FLAGS
def readeflags_u32 : X86Builtin<"unsigned int()"> {
let Attributes = [NoThrow];
}

def writeeflags_u32 : X86Builtin<"void(unsigned int)"> {
let Attributes = [NoThrow];
}

// MMX
//
// All MMX instructions will be generated via builtins. Any MMX vector
// types (<1 x i64>, <2 x i32>, etc.) that aren't used by these builtins will be
// expanded by the back-end.

def emms : X86Builtin<"void()"> {
let Attributes = [NoThrow];
let Features = "mmx";
}

let Attributes = [NoThrow, Const, RequiredVectorWidth<64>], Features = "sse" in {
def vec_ext_v4hi : X86Builtin<"short(_Vector<4, short>, _Constant int)">;
def vec_set_v4hi : X86Builtin<"_Vector<4, short>(_Vector<4, short>, short, _Constant int)">;
}

// SSE intrinsics
let Attributes = [Const, NoThrow, RequiredVectorWidth<128>] in {
foreach Cmp = ["eq", "lt", "le", "gt", "ge", "neq"] in {
let Features = "sse" in {
def comi#Cmp : X86Builtin<"int(_Vector<4, float>, _Vector<4, float>)">;
def ucomi#Cmp : X86Builtin<"int(_Vector<4, float>, _Vector<4, float>)">;
}
let Features = "sse2" in {
def comisd#Cmp : X86Builtin<"int(_Vector<2, double>, _Vector<2, double>)">;
def ucomisd#Cmp : X86Builtin<"int(_Vector<2, double>, _Vector<2, double>)">;
}
}

foreach Cmp = ["cmpeq", "cmplt", "cmple", "cmpunord", "cmpneq", "cmpnlt",
"cmpnle", "cmpord", "min", "max"] in {
let Features = "sse" in {
def Cmp#ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>)">;
def Cmp#ss : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>)">;
}
let Features = "sse2" in {
def Cmp#pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>)">;
def Cmp#sd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>)">;
}
}

let Features = "sse" in {
def cmpps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Constant char)">;
def cmpss : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>, _Constant char)">;
}

let Features = "sse2" in {
def cmppd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Constant char)">;
def cmpsd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>, _Constant char)">;
}

let Features = "sse2" in {
def pmulhw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def pavgb128 : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">;
def pavgw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def packsswb128 : X86Builtin<"_Vector<16, char>(_Vector<8, short>, _Vector<8, short>)">;
def packssdw128 : X86Builtin<"_Vector<8, short>(_Vector<4, int>, _Vector<4, int>)">;
def packuswb128 : X86Builtin<"_Vector<16, char>(_Vector<8, short>, _Vector<8, short>)">;
def pmulhuw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def vec_ext_v2di : X86Builtin<"long long int(_Vector<2, long long int>, _Constant int)">;
def vec_ext_v4si : X86Builtin<"int(_Vector<4, int>, _Constant int)">;
def vec_ext_v4sf : X86Builtin<"float(_Vector<4, float>, _Constant int)">;
def vec_ext_v8hi : X86Builtin<"short(_Vector<8, short>, _Constant int)">;
def vec_set_v8hi : X86Builtin<"_Vector<8, short>(_Vector<8, short>, short, _Constant int)">;
}

let Features = "sse3" in {
foreach Op = ["addsub", "hadd", "hsub"] in {
def Op#ps : X86Builtin<"_Vector<4, float>(_Vector<4, float>, _Vector<4, float>)">;
def Op#pd : X86Builtin<"_Vector<2, double>(_Vector<2, double>, _Vector<2, double>)">;
}
}

let Features = "ssse3" in {
foreach Op = ["phadd", "phsub"] in {
def Op#w128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def Op#sw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def Op#d128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
}

def pmaddubsw128 : X86Builtin<"_Vector<8, short>(_Vector<16, char>, _Vector<16, char>)">;
def pmulhrsw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def pshufb128 : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">;
def psignb128 : X86Builtin<"_Vector<16, char>(_Vector<16, char>, _Vector<16, char>)">;
def psignw128 : X86Builtin<"_Vector<8, short>(_Vector<8, short>, _Vector<8, short>)">;
def psignd128 : X86Builtin<"_Vector<4, int>(_Vector<4, int>, _Vector<4, int>)">;
}
}

// AVX
let Attributes = [Const, NoThrow, RequiredVectorWidth<256>], Features = "avx" in {
foreach Op = ["addsub", "hadd", "hsub", "max", "min"] in {
def Op#pd256 : X86Builtin<"_Vector<4, double>(_Vector<4, double>, _Vector<4, double>)">;
def Op#ps256 : X86Builtin<"_Vector<8, float>(_Vector<8, float>, _Vector<8, float>)">;
}
}
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/BuiltinsX86_64.def
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ TARGET_BUILTIN(__builtin_ia32_cmpccxadd64, "SLLiv*SLLiSLLiIi", "n", "cmpccxadd")
// AMX_FP16 FP16
TARGET_BUILTIN(__builtin_ia32_tdpfp16ps, "vIUcIUcIUc", "n", "amx-fp16")

// AMX FP8
TARGET_BUILTIN(__builtin_ia32_tdpbf8ps, "vIUcUIcUIc", "n", "amx-fp8")
TARGET_BUILTIN(__builtin_ia32_tdpbhf8ps, "vIUcUIcUIc", "n", "amx-fp8")
TARGET_BUILTIN(__builtin_ia32_tdphbf8ps, "vIUcUIcUIc", "n", "amx-fp8")
TARGET_BUILTIN(__builtin_ia32_tdphf8ps, "vIUcUIcUIc", "n", "amx-fp8")

// RAO-INT
TARGET_BUILTIN(__builtin_ia32_aadd64, "vv*SOi", "n", "raoint")
TARGET_BUILTIN(__builtin_ia32_aand64, "vv*SOi", "n", "raoint")
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ clang_tablegen(BuiltinsRISCV.inc -gen-clang-builtins
SOURCE BuiltinsRISCV.td
TARGET ClangBuiltinsRISCV)

clang_tablegen(BuiltinsX86.inc -gen-clang-builtins
SOURCE BuiltinsX86.td
TARGET ClangBuiltinsX86)

# ARM NEON and MVE
clang_tablegen(arm_neon.inc -gen-arm-neon-sema
SOURCE arm_neon.td
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling")

LANGOPT(XLPragmaPack, 1, 0, "IBM XL #pragma pack handling")

LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")
COMPATIBLE_LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, "retain documentation comments from system headers in the AST")

LANGOPT(APINotes, 1, 0, "use external API notes")
LANGOPT(APINotesModules, 1, 0, "use module-based external API notes")
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/TargetBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ namespace clang {
LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1,
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/BuiltinsX86.def"
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/BuiltinsX86.inc"
FirstX86_64Builtin,
LastX86CommonBuiltin = FirstX86_64Builtin - 1,
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
Expand Down
13 changes: 6 additions & 7 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1786,12 +1786,6 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Emit extra debug info to make sample profile more accurate">,
NegFlag<SetFalse>>;
def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect coverage info for cold functions into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>, MetaVarName<"<directory>">,
HelpText<"Generate instrumented code to collect coverage info for cold functions into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
Expand Down Expand Up @@ -6300,6 +6294,8 @@ def mamx_fp16 : Flag<["-"], "mamx-fp16">, Group<m_x86_Features_Group>;
def mno_amx_fp16 : Flag<["-"], "mno-amx-fp16">, Group<m_x86_Features_Group>;
def mamx_int8 : Flag<["-"], "mamx-int8">, Group<m_x86_Features_Group>;
def mno_amx_int8 : Flag<["-"], "mno-amx-int8">, Group<m_x86_Features_Group>;
def mamx_fp8 : Flag<["-"], "mamx-fp8">, Group<m_x86_Features_Group>;
def mno_amx_fp8 : Flag<["-"], "mno-amx-fp8">, Group<m_x86_Features_Group>;
def mamx_tile : Flag<["-"], "mamx-tile">, Group<m_x86_Features_Group>;
def mno_amx_tile : Flag<["-"], "mno-amx-tile">, Group<m_x86_Features_Group>;
def mcmpccxadd : Flag<["-"], "mcmpccxadd">, Group<m_x86_Features_Group>;
Expand Down Expand Up @@ -6779,7 +6775,10 @@ def fsycl : Flag<["-"], "fsycl">,
def fno_sycl : Flag<["-"], "fno-sycl">,
Visibility<[ClangOption, CLOption]>,
Group<sycl_Group>, HelpText<"Disables SYCL kernels compilation for device">;

def sycl_link : Flag<["--"], "sycl-link">, Flags<[HelpHidden]>,
Visibility<[ClangOption, CLOption]>,
Group<sycl_Group>, HelpText<"Perform link through clang-sycl-linker via the target "
"offloading toolchain.">;
// OS-specific options
let Flags = [TargetSpecific] in {
defm android_pad_segment : BooleanFFlag<"android-pad-segment">, Group<f_Group>;
Expand Down
8 changes: 7 additions & 1 deletion clang/include/clang/Index/USRGeneration.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
namespace clang {
class ASTContext;
class Decl;
class LangOptions;
class MacroDefinitionRecord;
class Module;
class SourceLocation;
Expand All @@ -30,6 +31,8 @@ static inline StringRef getUSRSpacePrefix() {
/// Generate a USR for a Decl, including the USR prefix.
/// \returns true if the results should be ignored, false otherwise.
bool generateUSRForDecl(const Decl *D, SmallVectorImpl<char> &Buf);
bool generateUSRForDecl(const Decl *D, SmallVectorImpl<char> &Buf,
const LangOptions &LangOpts);

/// Generate a USR fragment for an Objective-C class.
void generateUSRForObjCClass(StringRef Cls, raw_ostream &OS,
Expand Down Expand Up @@ -75,7 +78,10 @@ bool generateUSRForMacro(StringRef MacroName, SourceLocation Loc,
/// Generates a USR for a type.
///
/// \return true on error, false on success.
bool generateUSRForType(QualType T, ASTContext &Ctx, SmallVectorImpl<char> &Buf);
bool generateUSRForType(QualType T, ASTContext &Ctx,
SmallVectorImpl<char> &Buf);
bool generateUSRForType(QualType T, ASTContext &Ctx, SmallVectorImpl<char> &Buf,
const LangOptions &LangOpts);

/// Generate a USR for a module, including the USR prefix.
/// \returns true on error, false on success.
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/SemaAMDGPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ class SemaAMDGPU : public SemaBase {

bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);

bool checkMovDPPFunctionCall(CallExpr *TheCall, unsigned NumArgs,
unsigned NumDataArgs);

/// Create an AMDGPUWavesPerEUAttr attribute.
AMDGPUFlatWorkGroupSizeAttr *
CreateAMDGPUFlatWorkGroupSizeAttr(const AttributeCommonInfo &CI, Expr *Min,
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang/Sema/SemaObjC.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,10 @@ class SemaObjC : public SemaBase {
ParsedAttributesView ArgAttrs;
};

ParmVarDecl *ActOnMethodParmDeclaration(Scope *S, ObjCArgInfo &ArgInfo,
int ParamIndex,
bool MethodDefinition);

Decl *ActOnMethodDeclaration(
Scope *S,
SourceLocation BeginLoc, // location of the + or -.
Expand All @@ -359,7 +363,7 @@ class SemaObjC : public SemaBase {
ArrayRef<SourceLocation> SelectorLocs, Selector Sel,
// optional arguments. The number of types/arguments is obtained
// from the Sel.getNumArgs().
ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo,
ParmVarDecl **ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo,
unsigned CNumArgs, // c-style args
const ParsedAttributesView &AttrList, tok::ObjCKeywordKind MethodImplKind,
bool isVariadic, bool MethodDefinition);
Expand Down
44 changes: 42 additions & 2 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/Bitstream/BitstreamReader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/VersionTuple.h"
#include <cassert>
Expand Down Expand Up @@ -1341,9 +1342,48 @@ class ASTReader
serialization::InputFile getInputFile(ModuleFile &F, unsigned ID,
bool Complain = true);

/// The buffer used as the temporary backing storage for resolved paths.
SmallString<0> PathBuf;

/// A wrapper around StringRef that temporarily borrows the underlying buffer.
class TemporarilyOwnedStringRef {
StringRef String;
llvm::SaveAndRestore<SmallString<0>> UnderlyingBuffer;

public:
TemporarilyOwnedStringRef(StringRef S, SmallString<0> &UnderlyingBuffer)
: String(S), UnderlyingBuffer(UnderlyingBuffer, {}) {}

/// Return the wrapped \c StringRef that must be outlived by \c this.
const StringRef *operator->() const & { return &String; }
const StringRef &operator*() const & { return String; }

/// Make it harder to get a \c StringRef that outlives \c this.
const StringRef *operator->() && = delete;
const StringRef &operator*() && = delete;
};

public:
void ResolveImportedPath(ModuleFile &M, std::string &Filename);
static void ResolveImportedPath(std::string &Filename, StringRef Prefix);
/// Get the buffer for resolving paths.
SmallString<0> &getPathBuf() { return PathBuf; }

/// Resolve \c Path in the context of module file \c M. The return value
/// must go out of scope before the next call to \c ResolveImportedPath.
static TemporarilyOwnedStringRef
ResolveImportedPath(SmallString<0> &Buf, StringRef Path, ModuleFile &ModF);
/// Resolve \c Path in the context of the \c Prefix directory. The return
/// value must go out of scope before the next call to \c ResolveImportedPath.
static TemporarilyOwnedStringRef
ResolveImportedPath(SmallString<0> &Buf, StringRef Path, StringRef Prefix);

/// Resolve \c Path in the context of module file \c M.
static std::string ResolveImportedPathAndAllocate(SmallString<0> &Buf,
StringRef Path,
ModuleFile &ModF);
/// Resolve \c Path in the context of the \c Prefix directory.
static std::string ResolveImportedPathAndAllocate(SmallString<0> &Buf,
StringRef Path,
StringRef Prefix);

/// Returns the first key declaration for the given declaration. This
/// is one that is formerly-canonical (or still canonical) and whose module
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/ASTRecordWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ class ASTRecordWriter
AddStmt(const_cast<Stmt*>(S));
}

void writeAttr(const Attr *A) { AddAttr(A); }

/// Write an BTFTypeTagAttr object.
void writeBTFTypeTagAttr(const BTFTypeTagAttr *A) { AddAttr(A); }

Expand Down
48 changes: 40 additions & 8 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3552,7 +3552,8 @@ ASTContext::adjustType(QualType Orig,
const auto *AT = dyn_cast<AttributedType>(Orig);
return getAttributedType(AT->getAttrKind(),
adjustType(AT->getModifiedType(), Adjust),
adjustType(AT->getEquivalentType(), Adjust));
adjustType(AT->getEquivalentType(), Adjust),
AT->getAttr());
}

case Type::BTFTagAttributed: {
Expand Down Expand Up @@ -5197,24 +5198,54 @@ QualType ASTContext::getUnresolvedUsingType(

QualType ASTContext::getAttributedType(attr::Kind attrKind,
QualType modifiedType,
QualType equivalentType) const {
QualType equivalentType,
const Attr *attr) const {
llvm::FoldingSetNodeID id;
AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
AttributedType::Profile(id, attrKind, modifiedType, equivalentType, attr);

void *insertPos = nullptr;
AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos);
if (type) return QualType(type, 0);

assert(!attr || attr->getKind() == attrKind);

QualType canon = getCanonicalType(equivalentType);
type = new (*this, alignof(AttributedType))
AttributedType(canon, attrKind, modifiedType, equivalentType);
type = new (*this, alignof(AttributedType))
AttributedType(canon, attrKind, attr, modifiedType, equivalentType);

Types.push_back(type);
AttributedTypes.InsertNode(type, insertPos);

return QualType(type, 0);
}

QualType ASTContext::getAttributedType(const Attr *attr, QualType modifiedType,
QualType equivalentType) const {
return getAttributedType(attr->getKind(), modifiedType, equivalentType, attr);
}

QualType ASTContext::getAttributedType(NullabilityKind nullability,
QualType modifiedType,
QualType equivalentType) {
switch (nullability) {
case NullabilityKind::NonNull:
return getAttributedType(attr::TypeNonNull, modifiedType, equivalentType);

case NullabilityKind::Nullable:
return getAttributedType(attr::TypeNullable, modifiedType, equivalentType);

case NullabilityKind::NullableResult:
return getAttributedType(attr::TypeNullableResult, modifiedType,
equivalentType);

case NullabilityKind::Unspecified:
return getAttributedType(attr::TypeNullUnspecified, modifiedType,
equivalentType);
}

llvm_unreachable("Unknown nullability kind");
}

QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
QualType Wrapped) const {
llvm::FoldingSetNodeID ID;
Expand Down Expand Up @@ -7537,8 +7568,8 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) const {

// int x[_Nullable] -> int * _Nullable
if (auto Nullability = Ty->getNullability()) {
Result = const_cast<ASTContext *>(this)->getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability), Result, Result);
Result = const_cast<ASTContext *>(this)->getAttributedType(*Nullability,
Result, Result);
}
return Result;
}
Expand Down Expand Up @@ -13773,7 +13804,8 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
return QualType();
// FIXME: It's inefficient to have to unify the modified types.
return Ctx.getAttributedType(Kind, Ctx.getCommonSugaredType(MX, MY),
Ctx.getQualifiedType(Underlying));
Ctx.getQualifiedType(Underlying),
AX->getAttr());
}
case Type::BTFTagAttributed: {
const auto *BX = cast<BTFTagAttributedType>(X);
Expand Down
6 changes: 2 additions & 4 deletions clang/lib/AST/ASTDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
QualType SugarRT = FT->getReturnType();
QualType RT = desugarForDiagnostic(Context, SugarRT, DesugarReturn);
if (auto nullability = AttributedType::stripOuterNullability(SugarRT)) {
RT = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*nullability), RT, RT);
RT = Context.getAttributedType(*nullability, RT, RT);
}

bool DesugarArgument = false;
Expand All @@ -97,8 +96,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
QualType PT = desugarForDiagnostic(Context, SugarPT, DesugarArgument);
if (auto nullability =
AttributedType::stripOuterNullability(SugarPT)) {
PT = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*nullability), PT, PT);
PT = Context.getAttributedType(*nullability, PT, PT);
}
Args.push_back(PT);
}
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1580,8 +1580,9 @@ ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) {
if (!ToEquivalentTypeOrErr)
return ToEquivalentTypeOrErr.takeError();

return Importer.getToContext().getAttributedType(T->getAttrKind(),
*ToModifiedTypeOrErr, *ToEquivalentTypeOrErr);
return Importer.getToContext().getAttributedType(
T->getAttrKind(), *ToModifiedTypeOrErr, *ToEquivalentTypeOrErr,
T->getAttr());
}

ExpectedType
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/ByteCode/Boolean.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ class Boolean final {

Boolean truncate(unsigned TruncBits) const { return *this; }

static Boolean bitcastFromMemory(const std::byte *Buff, unsigned BitWidth) {
// Boolean width is currently always 8 for all supported targets. If this
// changes we need to get the bool width from the target info.
assert(BitWidth == 8);
bool Val = static_cast<bool>(*Buff);
return Boolean(Val);
}

void bitcastToMemory(std::byte *Buff) { std::memcpy(Buff, &V, sizeof(V)); }

void print(llvm::raw_ostream &OS) const { OS << (V ? "true" : "false"); }
std::string toDiagnosticString(const ASTContext &Ctx) const {
std::string NameStr;
Expand Down
63 changes: 63 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitDecayPtr(*FromT, *ToT, CE);
}

case CK_LValueToRValueBitCast:
return this->emitBuiltinBitCast(CE);

case CK_IntegralToBoolean:
case CK_FixedPointToBoolean:
case CK_BooleanToSignedIntegral:
Expand Down Expand Up @@ -6426,6 +6429,66 @@ bool Compiler<Emitter>::emitDummyPtr(const DeclTy &D, const Expr *E) {
return this->emitDecayPtr(PT_Ptr, PT, E);
return false;
}
return true;
}

// This function is constexpr if and only if To, From, and the types of
// all subobjects of To and From are types T such that...
// (3.1) - is_union_v<T> is false;
// (3.2) - is_pointer_v<T> is false;
// (3.3) - is_member_pointer_v<T> is false;
// (3.4) - is_volatile_v<T> is false; and
// (3.5) - T has no non-static data members of reference type
template <class Emitter>
bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
const Expr *SubExpr = E->getSubExpr();
QualType FromType = SubExpr->getType();
QualType ToType = E->getType();
std::optional<PrimType> ToT = classify(ToType);

assert(!DiscardResult && "Implement DiscardResult mode for bitcasts.");

if (ToType->isNullPtrType()) {
if (!this->discard(SubExpr))
return false;

return this->emitNullPtr(nullptr, E);
}

if (FromType->isNullPtrType() && ToT) {
if (!this->discard(SubExpr))
return false;

return visitZeroInitializer(*ToT, ToType, E);
}
assert(!ToType->isReferenceType());

// Get a pointer to the value-to-cast on the stack.
if (!this->visit(SubExpr))
return false;

if (!ToT || ToT == PT_Ptr) {
// Conversion to an array or record type.
assert(false && "Implement bitcast to pointers.");
}
assert(ToT);

const llvm::fltSemantics *TargetSemantics = nullptr;
if (ToT == PT_Float)
TargetSemantics = &Ctx.getFloatSemantics(ToType);

// Conversion to a primitive type. FromType can be another
// primitive type, or a record/array.
bool ToTypeIsUChar = (ToType->isSpecificBuiltinType(BuiltinType::UChar) ||
ToType->isSpecificBuiltinType(BuiltinType::Char_U));
uint32_t ResultBitWidth = std::max(Ctx.getBitWidth(ToType), 8u);

if (!this->emitBitCast(*ToT, ToTypeIsUChar || ToType->isStdByteType(),
ResultBitWidth, TargetSemantics, E))
return false;

if (DiscardResult)
return this->emitPop(*ToT, E);

return true;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
unsigned collectBaseOffset(const QualType BaseType,
const QualType DerivedType);
bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
bool emitBuiltinBitCast(const CastExpr *E);
bool compileConstructor(const CXXConstructorDecl *Ctor);
bool compileDestructor(const CXXDestructorDecl *Dtor);

Expand Down
10 changes: 9 additions & 1 deletion clang/lib/AST/ByteCode/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,16 @@ QualType Descriptor::getElemQualType() const {
QualType T = getType();
if (T->isPointerOrReferenceType())
return T->getPointeeType();
if (const auto *AT = T->getAsArrayTypeUnsafe())
if (const auto *AT = T->getAsArrayTypeUnsafe()) {
// For primitive arrays, we don't save a QualType at all,
// just a PrimType. Try to figure out the QualType here.
if (isPrimitiveArray()) {
while (T->isArrayType())
T = T->getAsArrayTypeUnsafe()->getElementType();
return T;
}
return AT->getElementType();
}
if (const auto *CT = T->getAs<ComplexType>())
return CT->getElementType();
if (const auto *CT = T->getAs<VectorType>())
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/ByteCode/Floating.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ class Floating final {
return Floating(APFloat(Sem, API));
}

void bitcastToMemory(std::byte *Buff) {
llvm::APInt API = F.bitcastToAPInt();
llvm::StoreIntToMemory(API, (uint8_t *)Buff, bitWidth() / 8);
}

// === Serialization support ===
size_t bytesToSerialize() const {
return sizeof(llvm::fltSemantics *) +
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ template <unsigned Bits, bool Signed> class Integral final {
// The primitive representing the integral.
using ReprT = typename Repr<Bits, Signed>::Type;
ReprT V;
static_assert(std::is_trivially_copyable_v<ReprT>);

/// Primitive representing limits.
static const auto Min = std::numeric_limits<ReprT>::min();
Expand Down Expand Up @@ -154,6 +155,18 @@ template <unsigned Bits, bool Signed> class Integral final {
return Compare(V, RHS.V);
}

void bitcastToMemory(std::byte *Dest) const {
std::memcpy(Dest, &V, sizeof(V));
}

static Integral bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
assert(BitWidth == sizeof(ReprT) * 8);
ReprT V;

std::memcpy(&V, Src, sizeof(ReprT));
return Integral(V);
}

std::string toDiagnosticString(const ASTContext &Ctx) const {
std::string NameStr;
llvm::raw_string_ostream OS(NameStr);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/ByteCode/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@ template <bool Signed> class IntegralAP final {
return IntegralAP<false>(Copy);
}

void bitcastToMemory(std::byte *Dest) const { assert(false); }

static IntegralAP bitcastFromMemory(const std::byte *Src, unsigned BitWidth) {
return IntegralAP();
}

ComparisonCategoryResult compare(const IntegralAP &RHS) const {
assert(Signed == RHS.isSigned());
assert(bitWidth() == RHS.bitWidth());
Expand Down
35 changes: 35 additions & 0 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,13 @@ static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);
}

static bool hasVirtualDestructor(QualType T) {
if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
if (const CXXDestructorDecl *DD = RD->getDestructor())
return DD->isVirtual();
return false;
}

bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
bool IsGlobalDelete) {
if (!CheckDynamicMemoryAllocation(S, OpPC))
Expand All @@ -1019,9 +1026,20 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
return true;

// Remove base casts.
QualType InitialType = Ptr.getType();
while (Ptr.isBaseClass())
Ptr = Ptr.getBase();

// For the non-array case, the types must match if the static type
// does not have a virtual destructor.
if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
!hasVirtualDestructor(InitialType)) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_delete_base_nonvirt_dtor)
<< InitialType << Ptr.getType();
return false;
}

if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
Expand Down Expand Up @@ -1556,6 +1574,23 @@ bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
return true;
}

bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
bool TargetIsUCharOrByte) {
// This is always fine.
if (!HasIndeterminateBits)
return true;

// Indeterminate bits can only be bitcast to unsigned char or std::byte.
if (TargetIsUCharOrByte)
return true;

const Expr *E = S.Current->getExpr(OpPC);
QualType ExprType = E->getType();
S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
<< ExprType << S.getLangOpts().CharIsSigned << E->getSourceRange();
return false;
}

// https://github.com/llvm/llvm-project/issues/102513
#if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)
#pragma optimize("", off)
Expand Down
41 changes: 39 additions & 2 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "Floating.h"
#include "Function.h"
#include "FunctionPointer.h"
#include "InterpBuiltinBitCast.h"
#include "InterpFrame.h"
#include "InterpStack.h"
#include "InterpState.h"
Expand Down Expand Up @@ -162,6 +163,8 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
const CallExpr *CE);
bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);
bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);
bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
bool TargetIsUCharOrByte);

template <typename T>
static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {
Expand Down Expand Up @@ -273,8 +276,14 @@ bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,
*NumElements > MaxElements) {
if (!IsNoThrow) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_new_too_large)
<< NumElements->toDiagnosticString(S.getASTContext());

if (NumElements->isSigned() && NumElements->isNegative()) {
S.FFDiag(Loc, diag::note_constexpr_new_negative)
<< NumElements->toDiagnosticString(S.getASTContext());
} else {
S.FFDiag(Loc, diag::note_constexpr_new_too_large)
<< NumElements->toDiagnosticString(S.getASTContext());
}
}
return false;
}
Expand Down Expand Up @@ -3033,6 +3042,34 @@ bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {
return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));
}
bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool BitCast(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,
uint32_t ResultBitWidth, const llvm::fltSemantics *Sem) {
const Pointer &FromPtr = S.Stk.pop<Pointer>();

if (!CheckLoad(S, OpPC, FromPtr))
return false;

size_t BuffSize = ResultBitWidth / 8;
llvm::SmallVector<std::byte> Buff(BuffSize);
bool HasIndeterminateBits = false;

if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BuffSize, HasIndeterminateBits))
return false;

if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))
return false;

if constexpr (std::is_same_v<T, Floating>) {
assert(false && "Implement bitcasting to a floating type");
} else {
assert(!Sem);
S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));
}
return true;
}

//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Compiler.h"
#include "EvalEmitter.h"
#include "Interp.h"
#include "InterpBuiltinBitCast.h"
#include "PrimType.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/RecordLayout.h"
Expand Down
367 changes: 367 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,367 @@
//===-------------------- InterpBuiltinBitCast.cpp --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "InterpBuiltinBitCast.h"
#include "Boolean.h"
#include "Context.h"
#include "FixedPoint.h"
#include "Floating.h"
#include "Integral.h"
#include "IntegralAP.h"
#include "InterpState.h"
#include "MemberPointer.h"
#include "Pointer.h"
#include "Record.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/BitVector.h"
#include <bitset>

using namespace clang;
using namespace clang::interp;

/// Used to iterate over pointer fields.
using DataFunc =
llvm::function_ref<bool(const Pointer &P, PrimType Ty, size_t BitOffset)>;

#define BITCAST_TYPE_SWITCH(Expr, B) \
do { \
switch (Expr) { \
TYPE_SWITCH_CASE(PT_Sint8, B) \
TYPE_SWITCH_CASE(PT_Uint8, B) \
TYPE_SWITCH_CASE(PT_Sint16, B) \
TYPE_SWITCH_CASE(PT_Uint16, B) \
TYPE_SWITCH_CASE(PT_Sint32, B) \
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
TYPE_SWITCH_CASE(PT_IntAP, B) \
TYPE_SWITCH_CASE(PT_IntAPS, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
default: \
llvm_unreachable("Unhandled bitcast type"); \
} \
} while (0)

/// Float is a special case that sometimes needs the floating point semantics
/// to be available.
#define BITCAST_TYPE_SWITCH_WITH_FLOAT(Expr, B) \
do { \
switch (Expr) { \
TYPE_SWITCH_CASE(PT_Sint8, B) \
TYPE_SWITCH_CASE(PT_Uint8, B) \
TYPE_SWITCH_CASE(PT_Sint16, B) \
TYPE_SWITCH_CASE(PT_Uint16, B) \
TYPE_SWITCH_CASE(PT_Sint32, B) \
TYPE_SWITCH_CASE(PT_Uint32, B) \
TYPE_SWITCH_CASE(PT_Sint64, B) \
TYPE_SWITCH_CASE(PT_Uint64, B) \
TYPE_SWITCH_CASE(PT_IntAP, B) \
TYPE_SWITCH_CASE(PT_IntAPS, B) \
TYPE_SWITCH_CASE(PT_Bool, B) \
TYPE_SWITCH_CASE(PT_Float, B) \
default: \
llvm_unreachable("Unhandled bitcast type"); \
} \
} while (0)

static bool bitof(std::byte B, unsigned BitIndex) {
return (B & (std::byte{1} << BitIndex)) != std::byte{0};
}

static void swapBytes(std::byte *M, size_t N) {
for (size_t I = 0; I != (N / 2); ++I)
std::swap(M[I], M[N - 1 - I]);
}

/// Track what bits have been initialized to known values and which ones
/// have indeterminate value.
/// All offsets are in bits.
struct BitcastBuffer {
llvm::BitVector Data;

BitcastBuffer() = default;

size_t size() const { return Data.size(); }

const std::byte *data() const {
unsigned NBytes = Data.size() / 8;
unsigned BitVectorWordSize = sizeof(uintptr_t);
bool FullWord = (NBytes % BitVectorWordSize == 0);

// llvm::BitVector uses 64-bit fields internally, so when we have
// fewer bytes than that, we need to compensate for that on
// big endian hosts.
unsigned DataPlus;
if (llvm::sys::IsBigEndianHost)
DataPlus = BitVectorWordSize - (NBytes % BitVectorWordSize);
else
DataPlus = 0;

return reinterpret_cast<const std::byte *>(Data.getData().data()) +
(FullWord ? 0 : DataPlus);
}

bool allInitialized() const {
// FIXME: Implement.
return true;
}

void pushData(const std::byte *data, size_t BitOffset, size_t BitWidth,
bool BigEndianTarget) {
Data.reserve(BitOffset + BitWidth);

bool OnlyFullBytes = BitWidth % 8 == 0;
unsigned NBytes = BitWidth / 8;

size_t BitsHandled = 0;
// Read all full bytes first
for (size_t I = 0; I != NBytes; ++I) {
std::byte B =
BigEndianTarget ? data[NBytes - OnlyFullBytes - I] : data[I];
for (unsigned X = 0; X != 8; ++X) {
Data.push_back(bitof(B, X));
++BitsHandled;
}
}

if (BitsHandled == BitWidth)
return;

// Rest of the bits.
assert((BitWidth - BitsHandled) < 8);
std::byte B = BigEndianTarget ? data[0] : data[NBytes];
for (size_t I = 0, E = (BitWidth - BitsHandled); I != E; ++I) {
Data.push_back(bitof(B, I));
++BitsHandled;
}

assert(BitsHandled == BitWidth);
}
};

/// We use this to recursively iterate over all fields and elemends of a pointer
/// and extract relevant data for a bitcast.
static bool enumerateData(const Pointer &P, const Context &Ctx, size_t Offset,
DataFunc F) {
const Descriptor *FieldDesc = P.getFieldDesc();
assert(FieldDesc);

// Primitives.
if (FieldDesc->isPrimitive())
return F(P, FieldDesc->getPrimType(), Offset);

// Primitive arrays.
if (FieldDesc->isPrimitiveArray()) {
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
QualType ElemType = FieldDesc->getElemQualType();
size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType);
PrimType ElemT = *Ctx.classify(ElemType);
bool Ok = true;
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
unsigned Index = BigEndianTarget ? (FieldDesc->getNumElems() - 1 - I) : I;
Ok = Ok && F(P.atIndex(Index), ElemT, Offset);
Offset += ElemSizeInBits;
}
return Ok;
}

// Composite arrays.
if (FieldDesc->isCompositeArray()) {
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
QualType ElemType = FieldDesc->getElemQualType();
size_t ElemSizeInBits = Ctx.getASTContext().getTypeSize(ElemType);
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
unsigned Index = BigEndianTarget ? (FieldDesc->getNumElems() - 1 - I) : I;
enumerateData(P.atIndex(Index).narrow(), Ctx, Offset, F);
Offset += ElemSizeInBits;
}
return true;
}

// Records.
if (FieldDesc->isRecord()) {
bool BigEndianTarget = Ctx.getASTContext().getTargetInfo().isBigEndian();
const Record *R = FieldDesc->ElemRecord;
const ASTRecordLayout &Layout =
Ctx.getASTContext().getASTRecordLayout(R->getDecl());
bool Ok = true;

auto enumerateFields = [&]() -> void {
for (unsigned I = 0, N = R->getNumFields(); I != N; ++I) {
const Record::Field *Fi =
R->getField(BigEndianTarget ? (N - 1 - I) : I);
Pointer Elem = P.atField(Fi->Offset);
size_t BitOffset =
Offset + Layout.getFieldOffset(Fi->Decl->getFieldIndex());
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
}
};
auto enumerateBases = [&]() -> void {
for (unsigned I = 0, N = R->getNumBases(); I != N; ++I) {
const Record::Base *B = R->getBase(BigEndianTarget ? (N - 1 - I) : I);
Pointer Elem = P.atField(B->Offset);
CharUnits ByteOffset =
Layout.getBaseClassOffset(cast<CXXRecordDecl>(B->Decl));
size_t BitOffset = Offset + Ctx.getASTContext().toBits(ByteOffset);
Ok = Ok && enumerateData(Elem, Ctx, BitOffset, F);
}
};

if (BigEndianTarget) {
enumerateFields();
enumerateBases();
} else {
enumerateBases();
enumerateFields();
}

return Ok;
}

llvm_unreachable("Unhandled data type");
}

static bool enumeratePointerFields(const Pointer &P, const Context &Ctx,
DataFunc F) {
return enumerateData(P, Ctx, 0, F);
}

// This function is constexpr if and only if To, From, and the types of
// all subobjects of To and From are types T such that...
// (3.1) - is_union_v<T> is false;
// (3.2) - is_pointer_v<T> is false;
// (3.3) - is_member_pointer_v<T> is false;
// (3.4) - is_volatile_v<T> is false; and
// (3.5) - T has no non-static data members of reference type
//
// NOTE: This is a version of checkBitCastConstexprEligibilityType() in
// ExprConstant.cpp.
static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T,
bool IsToType) {
enum {
E_Union = 0,
E_Pointer,
E_MemberPointer,
E_Volatile,
E_Reference,
};
enum { C_Member, C_Base };

auto diag = [&](int Reason) -> bool {
const Expr *E = S.Current->getExpr(OpPC);
S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)
<< static_cast<int>(IsToType) << (Reason == E_Reference) << Reason
<< E->getSourceRange();
return false;
};
auto note = [&](int Construct, QualType NoteType, SourceRange NoteRange) {
S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)
<< NoteType << Construct << T << NoteRange;
return false;
};

T = T.getCanonicalType();

if (T->isUnionType())
return diag(E_Union);
if (T->isPointerType())
return diag(E_Pointer);
if (T->isMemberPointerType())
return diag(E_MemberPointer);
if (T.isVolatileQualified())
return diag(E_Volatile);

if (const RecordDecl *RD = T->getAsRecordDecl()) {
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
for (const CXXBaseSpecifier &BS : CXXRD->bases()) {
if (!CheckBitcastType(S, OpPC, BS.getType(), IsToType))
return note(C_Base, BS.getType(), BS.getBeginLoc());
}
}
for (const FieldDecl *FD : RD->fields()) {
if (FD->getType()->isReferenceType())
return diag(E_Reference);
if (!CheckBitcastType(S, OpPC, FD->getType(), IsToType))
return note(C_Member, FD->getType(), FD->getSourceRange());
}
}

if (T->isArrayType() &&
!CheckBitcastType(S, OpPC, S.getASTContext().getBaseElementType(T),
IsToType))
return false;

return true;
}

static bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr,
BitcastBuffer &Buffer, bool ReturnOnUninit) {
const ASTContext &ASTCtx = Ctx.getASTContext();
bool SwapData = (ASTCtx.getTargetInfo().isLittleEndian() !=
llvm::sys::IsLittleEndianHost);
bool BigEndianTarget = ASTCtx.getTargetInfo().isBigEndian();

return enumeratePointerFields(
FromPtr, Ctx,
[&](const Pointer &P, PrimType T, size_t BitOffset) -> bool {
if (!P.isInitialized()) {
assert(false && "Implement uninitialized value tracking");
return ReturnOnUninit;
}

assert(P.isInitialized());
// nullptr_t is a PT_Ptr for us, but it's still not std::is_pointer_v.
if (T == PT_Ptr)
assert(false && "Implement casting to pointer types");

CharUnits ObjectReprChars = ASTCtx.getTypeSizeInChars(P.getType());
unsigned BitWidth;
if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())
BitWidth = FD->getBitWidthValue(ASTCtx);
else
BitWidth = ASTCtx.toBits(ObjectReprChars);

llvm::SmallVector<std::byte> Buff(ObjectReprChars.getQuantity());
BITCAST_TYPE_SWITCH_WITH_FLOAT(T, {
T Val = P.deref<T>();
Val.bitcastToMemory(Buff.data());
});
if (SwapData)
swapBytes(Buff.data(), ObjectReprChars.getQuantity());

if (BitWidth != (Buff.size() * 8) && BigEndianTarget) {
Buffer.pushData(Buff.data() + (Buff.size() - 1 - (BitWidth / 8)),
BitOffset, BitWidth, BigEndianTarget);
} else {
Buffer.pushData(Buff.data(), BitOffset, BitWidth, BigEndianTarget);
}
return true;
});
}

bool clang::interp::DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
std::byte *Buff, size_t BuffSize,
bool &HasIndeterminateBits) {
assert(Ptr.isLive());
assert(Ptr.isBlockPointer());
assert(Buff);

BitcastBuffer Buffer;
if (!CheckBitcastType(S, OpPC, Ptr.getType(), /*IsToType=*/false))
return false;

bool Success = readPointerToBuffer(S.getContext(), Ptr, Buffer,
/*ReturnOnUninit=*/false);
assert(Buffer.size() == BuffSize * 8);

HasIndeterminateBits = !Buffer.allInitialized();
std::memcpy(Buff, Buffer.data(), BuffSize);

return Success;
}
26 changes: 26 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===------------------ InterpBuiltinBitCast.h ------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H
#define LLVM_CLANG_AST_INTERP_BUILITN_BIT_CAST_H

#include <cstddef>

namespace clang {
namespace interp {
class Pointer;
class InterpState;
class CodePtr;

bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
std::byte *Buff, size_t BuffSize, bool &HasIndeterminateBits);

} // namespace interp
} // namespace clang

#endif
10 changes: 10 additions & 0 deletions clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -837,3 +837,13 @@ def CheckNewTypeMismatchArray : Opcode {

def IsConstantContext: Opcode;
def CheckAllocations : Opcode;

def BitCastTypeClass : TypeClass {
let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, IntAP, IntAPS, Bool, Float];
}

def BitCast : Opcode {
let Types = [BitCastTypeClass];
let Args = [ArgBool, ArgUint32, ArgFltSemantics];
let HasGroup = 1;
}
24 changes: 17 additions & 7 deletions clang/lib/AST/ByteCode/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,26 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
// Build the path into the object.
Pointer Ptr = *this;
while (Ptr.isField() || Ptr.isArrayElement()) {

if (Ptr.isArrayRoot()) {
Path.push_back(APValue::LValuePathEntry(
{Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));
// An array root may still be an array element itself.
if (Ptr.isArrayElement()) {
Ptr = Ptr.expand();
unsigned Index = Ptr.getIndex();
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
Ptr = Ptr.getArray();
} else {
Path.push_back(APValue::LValuePathEntry(
{Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));

if (const auto *FD =
dyn_cast_if_present<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
Offset += getFieldOffset(FD);
if (const auto *FD =
dyn_cast_if_present<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
Offset += getFieldOffset(FD);

Ptr = Ptr.getBase();
Ptr = Ptr.getBase();
}
} else if (Ptr.isArrayElement()) {
Ptr = Ptr.expand();
unsigned Index;
Expand All @@ -219,7 +230,6 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {

QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));

Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
Ptr = Ptr.getArray();
} else {
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/ByteCode/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,10 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
}

// Arrays.
if (const auto ArrayType = Ty->getAsArrayTypeUnsafe()) {
if (const auto *ArrayType = Ty->getAsArrayTypeUnsafe()) {
QualType ElemTy = ArrayType->getElementType();
// Array of well-known bounds.
if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
if (const auto *CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
size_t NumElems = CAT->getZExtSize();
if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
// Arrays of primitives.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ add_clang_library(clangAST
ByteCode/Function.cpp
ByteCode/FunctionPointer.cpp
ByteCode/InterpBuiltin.cpp
ByteCode/InterpBuiltinBitCast.cpp
ByteCode/Floating.cpp
ByteCode/EvaluationResult.cpp
ByteCode/DynamicAllocator.cpp
Expand Down
52 changes: 24 additions & 28 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ class CXXNameMangler {
void mangleLambdaSig(const CXXRecordDecl *Lambda);
void mangleModuleNamePrefix(StringRef Name, bool IsPartition = false);
void mangleVendorQualifier(StringRef Name);
void mangleVendorType(StringRef Name);

private:

Expand Down Expand Up @@ -2891,6 +2892,10 @@ void CXXNameMangler::mangleVendorQualifier(StringRef name) {
Out << 'U' << name.size() << name;
}

void CXXNameMangler::mangleVendorType(StringRef name) {
Out << 'u' << name.size() << name;
}

void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
// <ref-qualifier> ::= R # lvalue reference
// ::= O # rvalue-reference
Expand Down Expand Up @@ -3413,8 +3418,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
if (T->getKind() == BuiltinType::SveBFloat16 && \
isCompatibleWith(LangOptions::ClangABI::Ver17)) { \
/* Prior to Clang 18.0 we used this incorrect mangled name */ \
type_name = "__SVBFloat16_t"; \
Out << "u" << type_name.size() << type_name; \
mangleVendorType("__SVBFloat16_t"); \
} else { \
type_name = MangledName; \
Out << (type_name == Name ? "u" : "") << type_name.size() << type_name; \
Expand All @@ -3436,35 +3440,30 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
Out << (type_name == Name ? "u" : "") << type_name.size() << type_name; \
break;
#include "clang/Basic/AArch64SVEACLETypes.def"
#define PPC_VECTOR_TYPE(Name, Id, Size) \
case BuiltinType::Id: \
type_name = #Name; \
Out << 'u' << type_name.size() << type_name; \
#define PPC_VECTOR_TYPE(Name, Id, Size) \
case BuiltinType::Id: \
mangleVendorType(#Name); \
break;
#include "clang/Basic/PPCTypes.def"
// TODO: Check the mangling scheme for RISC-V V.
#define RVV_TYPE(Name, Id, SingletonId) \
case BuiltinType::Id: \
type_name = Name; \
Out << 'u' << type_name.size() << type_name; \
mangleVendorType(Name); \
break;
#include "clang/Basic/RISCVVTypes.def"
#define WASM_REF_TYPE(InternalName, MangledName, Id, SingletonId, AS) \
case BuiltinType::Id: \
type_name = MangledName; \
Out << 'u' << type_name.size() << type_name; \
mangleVendorType(MangledName); \
break;
#include "clang/Basic/WebAssemblyReferenceTypes.def"
#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \
case BuiltinType::Id: \
type_name = Name; \
Out << 'u' << type_name.size() << type_name; \
mangleVendorType(Name); \
break;
#include "clang/Basic/AMDGPUTypes.def"
#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \
case BuiltinType::Id: \
type_name = #Name; \
Out << 'u' << type_name.size() << type_name; \
mangleVendorType(#Name); \
break;
#include "clang/Basic/HLSLIntangibleTypes.def"
}
Expand Down Expand Up @@ -4035,8 +4034,9 @@ void CXXNameMangler::mangleAArch64FixedSveVectorType(const VectorType *T) {
if (T->getVectorKind() == VectorKind::SveFixedLengthPredicate)
VecSizeInBits *= 8;

Out << "9__SVE_VLSI" << 'u' << TypeName.size() << TypeName << "Lj"
<< VecSizeInBits << "EE";
Out << "9__SVE_VLSI";
mangleVendorType(TypeName);
Out << "Lj" << VecSizeInBits << "EE";
}

void CXXNameMangler::mangleAArch64FixedSveVectorType(
Expand Down Expand Up @@ -4136,8 +4136,9 @@ void CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
}
TypeNameOS << "_t";

Out << "9__RVV_VLSI" << 'u' << TypeNameStr.size() << TypeNameStr << "Lj"
<< VecSizeInBits << "EE";
Out << "9__RVV_VLSI";
mangleVendorType(TypeNameStr);
Out << "Lj" << VecSizeInBits << "EE";
}

void CXXNameMangler::mangleRISCVFixedRVVVectorType(
Expand Down Expand Up @@ -4236,8 +4237,7 @@ void CXXNameMangler::mangleType(const ConstantMatrixType *T) {
// Mangle matrix types as a vendor extended type:
// u<Len>matrix_typeI<Rows><Columns><element type>E

StringRef VendorQualifier = "matrix_type";
Out << "u" << VendorQualifier.size() << VendorQualifier;
mangleVendorType("matrix_type");

Out << "I";
auto &ASTCtx = getASTContext();
Expand All @@ -4255,8 +4255,7 @@ void CXXNameMangler::mangleType(const ConstantMatrixType *T) {
void CXXNameMangler::mangleType(const DependentSizedMatrixType *T) {
// Mangle matrix types as a vendor extended type:
// u<Len>matrix_typeI<row expr><column expr><element type>E
StringRef VendorQualifier = "matrix_type";
Out << "u" << VendorQualifier.size() << VendorQualifier;
mangleVendorType("matrix_type");

Out << "I";
mangleTemplateArgExpr(T->getRowExpr());
Expand Down Expand Up @@ -4302,7 +4301,7 @@ void CXXNameMangler::mangleType(const ObjCObjectType *T) {
StringRef name = I->getName();
QualOS << name.size() << name;
}
Out << 'U' << QualStr.size() << QualStr;
mangleVendorQualifier(QualStr);
}

mangleType(T->getBaseType());
Expand Down Expand Up @@ -4436,8 +4435,6 @@ void CXXNameMangler::mangleType(const UnaryTransformType *T) {
// If this is dependent, we need to record that. If not, we simply
// mangle it as the underlying type since they are equivalent.
if (T->isDependentType()) {
Out << "u";

StringRef BuiltinName;
switch (T->getUTTKind()) {
#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
Expand All @@ -4446,7 +4443,7 @@ void CXXNameMangler::mangleType(const UnaryTransformType *T) {
break;
#include "clang/Basic/TransformTypeTraits.def"
}
Out << BuiltinName.size() << BuiltinName;
mangleVendorType(BuiltinName);
}

Out << "I";
Expand Down Expand Up @@ -5311,9 +5308,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity,
// <expression> ::= u <source-name> <template-arg>* E # vendor extension
const TypeTraitExpr *TTE = cast<TypeTraitExpr>(E);
NotPrimaryExpr();
Out << 'u';
llvm::StringRef Spelling = getTraitSpelling(TTE->getTrait());
Out << Spelling.size() << Spelling;
mangleVendorType(Spelling);
for (TypeSourceInfo *TSI : TTE->getArgs()) {
mangleType(TSI->getType());
}
Expand Down
Loading