28 changes: 10 additions & 18 deletions clang/bindings/python/tests/cindex/test_translation_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
from contextlib import contextmanager
import gc
import os
import sys
import tempfile
import unittest
from pathlib import Path

from clang.cindex import CursorKind
from clang.cindex import Cursor
Expand All @@ -22,8 +22,6 @@
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


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
6 changes: 3 additions & 3 deletions clang/bindings/python/tests/cindex/test_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,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 +459,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
17 changes: 0 additions & 17 deletions clang/bindings/python/tests/cindex/util.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
# 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

Expand Down Expand Up @@ -81,14 +70,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.
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
14 changes: 14 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
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 @@ -661,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
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
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
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -4507,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
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
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
8 changes: 2 additions & 6 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
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
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: 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
18 changes: 18 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
10 changes: 8 additions & 2 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,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
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
20 changes: 17 additions & 3 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1241,8 +1241,8 @@ struct SimpleTransformVisitor : public TypeVisitor<Derived, QualType> {
== T->getEquivalentType().getAsOpaquePtr())
return QualType(T, 0);

return Ctx.getAttributedType(T->getAttrKind(), modifiedType,
equivalentType);
return Ctx.getAttributedType(T->getAttrKind(), modifiedType, equivalentType,
T->getAttr());
}

QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
Expand Down Expand Up @@ -1545,7 +1545,8 @@ struct SubstObjCTypeArgsVisitor

// Rebuild the attributed type.
return Ctx.getAttributedType(newAttrType->getAttrKind(),
newAttrType->getModifiedType(), newEquivType);
newAttrType->getModifiedType(), newEquivType,
newAttrType->getAttr());
}
};

Expand Down Expand Up @@ -4115,6 +4116,19 @@ bool RecordType::hasConstFields() const {
return false;
}

AttributedType::AttributedType(QualType canon, const Attr *attr,
QualType modified, QualType equivalent)
: AttributedType(canon, attr->getKind(), attr, modified, equivalent) {}

AttributedType::AttributedType(QualType canon, attr::Kind attrKind,
const Attr *attr, QualType modified,
QualType equivalent)
: Type(Attributed, canon, equivalent->getDependence()), Attribute(attr),
ModifiedType(modified), EquivalentType(equivalent) {
AttributedTypeBits.AttrKind = attrKind;
assert(!attr || attr->getKind() == attrKind);
}

bool AttributedType::isQualifier() const {
// FIXME: Generate this with TableGen.
switch (getAttrKind()) {
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1934,6 +1934,14 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
return;
}

if (T->getAttrKind() == attr::SwiftAttr) {
if (auto *swiftAttr = dyn_cast_or_null<SwiftAttrAttr>(T->getAttr())) {
OS << " __attribute__((swift_attr(\"" << swiftAttr->getAttribute()
<< "\")))";
}
return;
}

OS << " __attribute__((";
switch (T->getAttrKind()) {
#define TYPE_ATTR(NAME)
Expand Down Expand Up @@ -1994,6 +2002,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::NonAllocating:
case attr::Blocking:
case attr::Allocating:
case attr::SwiftAttr:
llvm_unreachable("This attribute should have been handled already");

case attr::NSReturnsRetained:
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1714,7 +1714,7 @@ void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts,
if (Triple.isArm64e())
Builder.defineMacro("__arm64e__", "1");

getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion);
DarwinTargetInfo<AArch64leTargetInfo>::getOSDefines(Opts, Triple, Builder);
}

TargetInfo::BuiltinVaListKind
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasAMXTILE = true;
} else if (Feature == "+amx-complex") {
HasAMXCOMPLEX = true;
} else if (Feature == "+amx-fp8") {
HasAMXFP8 = true;
} else if (Feature == "+cmpccxadd") {
HasCMPCCXADD = true;
} else if (Feature == "+raoint") {
Expand Down Expand Up @@ -947,6 +949,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__AMX_FP16__");
if (HasAMXCOMPLEX)
Builder.defineMacro("__AMX_COMPLEX__");
if (HasAMXFP8)
Builder.defineMacro("__AMX_FP8__");
if (HasCMPCCXADD)
Builder.defineMacro("__CMPCCXADD__");
if (HasRAOINT)
Expand Down Expand Up @@ -1077,6 +1081,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("amx-fp16", true)
.Case("amx-int8", true)
.Case("amx-tile", true)
.Case("amx-fp8", true)
.Case("avx", true)
.Case("avx10.1-256", true)
.Case("avx10.1-512", true)
Expand Down Expand Up @@ -1195,6 +1200,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("amx-fp16", HasAMXFP16)
.Case("amx-int8", HasAMXINT8)
.Case("amx-tile", HasAMXTILE)
.Case("amx-fp8", HasAMXFP8)
.Case("avx", SSELevel >= AVX)
.Case("avx10.1-256", HasAVX10_1)
.Case("avx10.1-512", HasAVX10_1_512)
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasAMXINT8 = false;
bool HasAMXBF16 = false;
bool HasAMXCOMPLEX = false;
bool HasAMXFP8 = false;
bool HasSERIALIZE = false;
bool HasTSXLDTRK = false;
bool HasUSERMSR = false;
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/CodeGen/BackendUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1013,9 +1013,10 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
if (IsThinLTOPostLink)
PB.registerPipelineStartEPCallback(
[](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(LowerTypeTestsPass(/*ExportSummary=*/nullptr,
/*ImportSummary=*/nullptr,
/*DropTypeTests=*/true));
MPM.addPass(LowerTypeTestsPass(
/*ExportSummary=*/nullptr,
/*ImportSummary=*/nullptr,
/*DropTypeTests=*/lowertypetests::DropTestKind::Assume));
});

// Register callbacks to schedule sanitizer passes at the appropriate part
Expand Down
16 changes: 10 additions & 6 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19115,8 +19115,6 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
return emitBuiltinWithOneOverloadedType<2>(*this, E,
Intrinsic::amdgcn_ds_swizzle);
case AMDGPU::BI__builtin_amdgcn_mov_dpp8:
return emitBuiltinWithOneOverloadedType<2>(*this, E,
Intrinsic::amdgcn_mov_dpp8);
case AMDGPU::BI__builtin_amdgcn_mov_dpp:
case AMDGPU::BI__builtin_amdgcn_update_dpp: {
llvm::SmallVector<llvm::Value *, 6> Args;
Expand All @@ -19130,14 +19128,20 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
unsigned Size = DataTy->getPrimitiveSizeInBits();
llvm::Type *IntTy =
llvm::IntegerType::get(Builder.getContext(), std::max(Size, 32u));
Function *F = CGM.getIntrinsic(Intrinsic::amdgcn_update_dpp, IntTy);
assert(E->getNumArgs() == 5 || E->getNumArgs() == 6);
bool InsertOld = E->getNumArgs() == 5;
Function *F =
CGM.getIntrinsic(BuiltinID == AMDGPU::BI__builtin_amdgcn_mov_dpp8
? Intrinsic::amdgcn_mov_dpp8
: Intrinsic::amdgcn_update_dpp,
IntTy);
assert(E->getNumArgs() == 5 || E->getNumArgs() == 6 ||
E->getNumArgs() == 2);
bool InsertOld = BuiltinID == AMDGPU::BI__builtin_amdgcn_mov_dpp;
if (InsertOld)
Args.push_back(llvm::PoisonValue::get(IntTy));
for (unsigned I = 0; I != E->getNumArgs(); ++I) {
llvm::Value *V = EmitScalarOrConstFoldImmArg(ICEArguments, I, E);
if (I <= (InsertOld ? 0u : 1u) && Size < 32) {
if (I < (BuiltinID == AMDGPU::BI__builtin_amdgcn_update_dpp ? 2u : 1u) &&
Size < 32) {
if (!DataTy->isIntegerTy())
V = Builder.CreateBitCast(
V, llvm::IntegerType::get(Builder.getContext(), Size));
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,9 +899,7 @@ bool ToolChain::needsProfileRT(const ArgList &Args) {
Args.hasArg(options::OPT_fprofile_instr_generate) ||
Args.hasArg(options::OPT_fprofile_instr_generate_EQ) ||
Args.hasArg(options::OPT_fcreate_profile) ||
Args.hasArg(options::OPT_forder_file_instrumentation) ||
Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage) ||
Args.hasArg(options::OPT_fprofile_generate_cold_function_coverage_EQ);
Args.hasArg(options::OPT_forder_file_instrumentation);
}

bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) {
Expand Down
20 changes: 0 additions & 20 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -632,26 +632,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
}
}

if (auto *ColdFuncCoverageArg = Args.getLastArg(
options::OPT_fprofile_generate_cold_function_coverage,
options::OPT_fprofile_generate_cold_function_coverage_EQ)) {
SmallString<128> Path(
ColdFuncCoverageArg->getOption().matches(
options::OPT_fprofile_generate_cold_function_coverage_EQ)
? ColdFuncCoverageArg->getValue()
: "");
llvm::sys::path::append(Path, "default_%m.profraw");
// FIXME: Idealy the file path should be passed through
// `-fprofile-instrument-path=`(InstrProfileOutput), however, this field is
// shared with other profile use path(see PGOOptions), we need to refactor
// PGOOptions to make it work.
CmdArgs.push_back("-mllvm");
CmdArgs.push_back(Args.MakeArgString(
Twine("--instrument-cold-function-only-path=") + Path));
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("--pgo-function-entry-coverage");
}

Arg *PGOGenArg = nullptr;
if (PGOGenerateArg) {
assert(!CSPGOGenerateArg);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ set(x86_files
amxcomplexintrin.h
amxfp16intrin.h
amxintrin.h
amxfp8intrin.h
avx10_2_512bf16intrin.h
avx10_2_512convertintrin.h
avx10_2_512minmaxintrin.h
Expand Down
95 changes: 95 additions & 0 deletions clang/lib/Headers/amxfp8intrin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*===------------- amxfp8intrin.h - AMX intrinsics -*- 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 __IMMINTRIN_H
#error "Never use <amxfp8intrin.h> directly; include <immintrin.h> instead."
#endif /* __IMMINTRIN_H */

#ifndef __AMXFP8INTRIN_H
#define __AMXFP8INTRIN_H
#ifdef __x86_64__

/// Peform the dot product of a BF8 value \a a by a BF8 value \a b accumulating
/// into a Single Precision (FP32) source/dest \a dst.
///
/// \headerfile <immintrin.h>
///
/// \code
/// void _tile_dpbf8ps (__tile dst, __tile a, __tile b)
/// \endcode
///
/// This intrinsic corresponds to the \c TDPBF8PS instruction.
///
/// \param dst
/// The destination tile. Max size is 1024 Bytes.
/// \param a
/// The 1st source tile. Max size is 1024 Bytes.
/// \param b
/// The 2nd source tile. Max size is 1024 Bytes.
#define _tile_dpbf8ps(dst, a, b) __builtin_ia32_tdpbf8ps((dst), (a), (b))

/// Perform the dot product of a BF8 value \a a by an HF8 value \a b
/// accumulating into a Single Precision (FP32) source/dest \a dst.
///
/// \headerfile <immintrin.h>
///
/// \code
/// void _tile_dpbhf8ps (__tile dst, __tile a, __tile b)
/// \endcode
///
/// This intrinsic corresponds to the \c TDPBHF8PS instruction.
///
/// \param dst
/// The destination tile. Max size is 1024 Bytes.
/// \param a
/// The 1st source tile. Max size is 1024 Bytes.
/// \param b
/// The 2nd source tile. Max size is 1024 Bytes.
#define _tile_dpbhf8ps(dst, a, b) __builtin_ia32_tdpbhf8ps((dst), (a), (b))

/// Perform the dot product of an HF8 value \a a by a BF8 value \a b
/// accumulating into a Single Precision (FP32) source/dest \a dst.
///
/// \headerfile <immintrin.h>
///
/// \code
/// void _tile_dphbf8ps (__tile dst, __tile a, __tile b)
/// \endcode
///
/// This intrinsic corresponds to the \c TDPHBF8PS instruction.
///
/// \param dst
/// The destination tile. Max size is 1024 Bytes.
/// \param a
/// The 1st source tile. Max size is 1024 Bytes.
/// \param b
/// The 2nd source tile. Max size is 1024 Bytes.
#define _tile_dphbf8ps(dst, a, b) __builtin_ia32_tdphbf8ps((dst), (a), (b))

/// Perform the dot product of an HF8 value \a a by an HF8 value \a b
/// accumulating into a Single Precision (FP32) source/dest \a dst.
///
/// \headerfile <immintrin.h>
///
/// \code
/// void _tile_dphf8ps (__tile dst, __tile a, __tile b)
/// \endcode
///
/// This intrinsic corresponds to the \c TDPHF8PS instruction.
///
/// \param dst
/// The destination tile. Max size is 1024 Bytes.
/// \param a
/// The 1st source tile. Max size is 1024 Bytes.
/// \param b
/// The 2nd source tile. Max size is 1024 Bytes.
#define _tile_dphf8ps(dst, a, b) __builtin_ia32_tdphf8ps((dst), (a), (b))

#endif /* __x86_64__ */
#endif /* __AMXFP8INTRIN_H */
4 changes: 4 additions & 0 deletions clang/lib/Headers/immintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,10 @@ _storebe_i64(void * __P, long long __D) {
#include <amxcomplexintrin.h>
#endif

#if !defined(__SCE__) || __has_feature(modules) || defined(__AMX_FP8__)
#include <amxfp8intrin.h>
#endif

#if !defined(__SCE__) || __has_feature(modules) || \
defined(__AVX512VP2INTERSECT__)
#include <avx512vp2intersectintrin.h>
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Parse/ParseObjc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,

SmallVector<const IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
SmallVector<SemaObjC::ObjCArgInfo, 12> ArgInfos;
SmallVector<ParmVarDecl *, 12> ObjCParamInfo;
ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
Scope::FunctionDeclarationScope | Scope::DeclScope);

Expand Down Expand Up @@ -1495,7 +1495,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
ArgInfo.NameLoc = Tok.getLocation();
ConsumeToken(); // Eat the identifier.

ArgInfos.push_back(ArgInfo);
ParmVarDecl *Param = Actions.ObjC().ActOnMethodParmDeclaration(
getCurScope(), ArgInfo, ObjCParamInfo.size(), MethodDefinition);
ObjCParamInfo.push_back(Param);
KeyIdents.push_back(SelIdent);
KeyLocs.push_back(selLoc);

Expand Down Expand Up @@ -1567,8 +1569,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
&KeyIdents[0]);
Decl *Result = Actions.ObjC().ActOnMethodDeclaration(
getCurScope(), mLoc, Tok.getLocation(), mType, DSRet, ReturnType, KeyLocs,
Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), methodAttrs,
MethodImplKind, isVariadic, MethodDefinition);
Sel, ObjCParamInfo.data(), CParamInfo.data(), CParamInfo.size(),
methodAttrs, MethodImplKind, isVariadic, MethodDefinition);

PD.complete(Result);
return Result;
Expand Down
85 changes: 43 additions & 42 deletions clang/lib/Sema/SemaAMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,49 +63,12 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
OrderIndex = 0;
ScopeIndex = 1;
break;
case AMDGPU::BI__builtin_amdgcn_mov_dpp: {
if (SemaRef.checkArgCountRange(TheCall, 5, 5))
return true;
Expr *ValArg = TheCall->getArg(0);
QualType Ty = ValArg->getType();
// TODO: Vectors can also be supported.
if (!Ty->isArithmeticType() || Ty->isAnyComplexType()) {
SemaRef.Diag(ValArg->getBeginLoc(),
diag::err_typecheck_cond_expect_int_float)
<< Ty << ValArg->getSourceRange();
return true;
}
return false;
}
case AMDGPU::BI__builtin_amdgcn_mov_dpp:
return checkMovDPPFunctionCall(TheCall, 5, 1);
case AMDGPU::BI__builtin_amdgcn_mov_dpp8:
return checkMovDPPFunctionCall(TheCall, 2, 1);
case AMDGPU::BI__builtin_amdgcn_update_dpp: {
if (SemaRef.checkArgCountRange(TheCall, 6, 6))
return true;
Expr *Args[2];
QualType ArgTys[2];
for (unsigned I = 0; I != 2; ++I) {
Args[I] = TheCall->getArg(I);
ArgTys[I] = Args[I]->getType();
// TODO: Vectors can also be supported.
if (!ArgTys[I]->isArithmeticType() || ArgTys[I]->isAnyComplexType()) {
SemaRef.Diag(Args[I]->getBeginLoc(),
diag::err_typecheck_cond_expect_int_float)
<< ArgTys[I] << Args[I]->getSourceRange();
return true;
}
}
if (getASTContext().hasSameUnqualifiedType(ArgTys[0], ArgTys[1]))
return false;
if (((ArgTys[0]->isUnsignedIntegerType() &&
ArgTys[1]->isSignedIntegerType()) ||
(ArgTys[0]->isSignedIntegerType() &&
ArgTys[1]->isUnsignedIntegerType())) &&
getASTContext().getTypeSize(ArgTys[0]) ==
getASTContext().getTypeSize(ArgTys[1]))
return false;
SemaRef.Diag(Args[1]->getBeginLoc(),
diag::err_typecheck_call_different_arg_types)
<< ArgTys[0] << ArgTys[1];
return true;
return checkMovDPPFunctionCall(TheCall, 6, 2);
}
default:
return false;
Expand Down Expand Up @@ -152,6 +115,44 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
return false;
}

bool SemaAMDGPU::checkMovDPPFunctionCall(CallExpr *TheCall, unsigned NumArgs,
unsigned NumDataArgs) {
assert(NumDataArgs <= 2);
if (SemaRef.checkArgCountRange(TheCall, NumArgs, NumArgs))
return true;
Expr *Args[2];
QualType ArgTys[2];
for (unsigned I = 0; I != NumDataArgs; ++I) {
Args[I] = TheCall->getArg(I);
ArgTys[I] = Args[I]->getType();
// TODO: Vectors can also be supported.
if (!ArgTys[I]->isArithmeticType() || ArgTys[I]->isAnyComplexType()) {
SemaRef.Diag(Args[I]->getBeginLoc(),
diag::err_typecheck_cond_expect_int_float)
<< ArgTys[I] << Args[I]->getSourceRange();
return true;
}
}
if (NumDataArgs < 2)
return false;

if (getASTContext().hasSameUnqualifiedType(ArgTys[0], ArgTys[1]))
return false;

if (((ArgTys[0]->isUnsignedIntegerType() &&
ArgTys[1]->isSignedIntegerType()) ||
(ArgTys[0]->isSignedIntegerType() &&
ArgTys[1]->isUnsignedIntegerType())) &&
getASTContext().getTypeSize(ArgTys[0]) ==
getASTContext().getTypeSize(ArgTys[1]))
return false;

SemaRef.Diag(Args[1]->getBeginLoc(),
diag::err_typecheck_call_different_arg_types)
<< ArgTys[0] << ArgTys[1];
return true;
}

static bool
checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
const AMDGPUFlatWorkGroupSizeAttr &Attr) {
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3332,9 +3332,7 @@ static void mergeParamDeclTypes(ParmVarDecl *NewParam,
}
} else {
QualType NewT = NewParam->getType();
NewT = S.Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Oldnullability),
NewT, NewT);
NewT = S.Context.getAttributedType(*Oldnullability, NewT, NewT);
NewParam->setType(NewT);
}
}
Expand Down
116 changes: 59 additions & 57 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4572,9 +4572,7 @@ static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc,
return type;

// Otherwise, provide the result with the same nullability.
return S.Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*prevNullability),
type, type);
return S.Context.getAttributedType(*prevNullability, type, type);
}

/// Merge information from the declaration of a method in the \@interface
Expand Down Expand Up @@ -4720,13 +4718,67 @@ static void checkObjCDirectMethodClashes(Sema &S, ObjCInterfaceDecl *IDecl,
diagClash(IMD);
}

ParmVarDecl *SemaObjC::ActOnMethodParmDeclaration(Scope *S,
ObjCArgInfo &ArgInfo,
int ParamIndex,
bool MethodDefinition) {
ASTContext &Context = getASTContext();
QualType ArgType;
TypeSourceInfo *DI;

if (!ArgInfo.Type) {
ArgType = Context.getObjCIdType();
DI = nullptr;
} else {
ArgType = SemaRef.GetTypeFromParser(ArgInfo.Type, &DI);
}
LookupResult R(SemaRef, ArgInfo.Name, ArgInfo.NameLoc,
Sema::LookupOrdinaryName,
SemaRef.forRedeclarationInCurContext());
SemaRef.LookupName(R, S);
if (R.isSingleResult()) {
NamedDecl *PrevDecl = R.getFoundDecl();
if (S->isDeclScope(PrevDecl)) {
Diag(ArgInfo.NameLoc,
(MethodDefinition ? diag::warn_method_param_redefinition
: diag::warn_method_param_declaration))
<< ArgInfo.Name;
Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
}
}
SourceLocation StartLoc =
DI ? DI->getTypeLoc().getBeginLoc() : ArgInfo.NameLoc;

// Temporarily put parameter variables in the translation unit. This is what
// ActOnParamDeclarator does in the case of C arguments to the Objective-C
// method too.
ParmVarDecl *Param = SemaRef.CheckParameter(
Context.getTranslationUnitDecl(), StartLoc, ArgInfo.NameLoc, ArgInfo.Name,
ArgType, DI, SC_None);
Param->setObjCMethodScopeInfo(ParamIndex);
Param->setObjCDeclQualifier(
CvtQTToAstBitMask(ArgInfo.DeclSpec.getObjCDeclQualifier()));

// Apply the attributes to the parameter.
SemaRef.ProcessDeclAttributeList(SemaRef.TUScope, Param, ArgInfo.ArgAttrs);
SemaRef.AddPragmaAttributes(SemaRef.TUScope, Param);
if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
Param->setInvalidDecl();
}

S->AddDecl(Param);
SemaRef.IdResolver.AddDecl(Param);
return Param;
}

Decl *SemaObjC::ActOnMethodDeclaration(
Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc,
tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
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 MethodDeclKind,
bool isVariadic, bool MethodDefinition) {
Expand Down Expand Up @@ -4768,60 +4820,10 @@ Decl *SemaObjC::ActOnMethodDeclaration(
HasRelatedResultType);

SmallVector<ParmVarDecl*, 16> Params;

for (unsigned i = 0, e = Sel.getNumArgs(); i != e; ++i) {
QualType ArgType;
TypeSourceInfo *DI;

if (!ArgInfo[i].Type) {
ArgType = Context.getObjCIdType();
DI = nullptr;
} else {
ArgType = SemaRef.GetTypeFromParser(ArgInfo[i].Type, &DI);
}

LookupResult R(SemaRef, ArgInfo[i].Name, ArgInfo[i].NameLoc,
Sema::LookupOrdinaryName,
SemaRef.forRedeclarationInCurContext());
SemaRef.LookupName(R, S);
if (R.isSingleResult()) {
NamedDecl *PrevDecl = R.getFoundDecl();
if (S->isDeclScope(PrevDecl)) {
Diag(ArgInfo[i].NameLoc,
(MethodDefinition ? diag::warn_method_param_redefinition
: diag::warn_method_param_declaration))
<< ArgInfo[i].Name;
Diag(PrevDecl->getLocation(),
diag::note_previous_declaration);
}
}

SourceLocation StartLoc = DI
? DI->getTypeLoc().getBeginLoc()
: ArgInfo[i].NameLoc;

ParmVarDecl *Param =
SemaRef.CheckParameter(ObjCMethod, StartLoc, ArgInfo[i].NameLoc,
ArgInfo[i].Name, ArgType, DI, SC_None);

Param->setObjCMethodScopeInfo(i);

Param->setObjCDeclQualifier(
CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier()));

// Apply the attributes to the parameter.
SemaRef.ProcessDeclAttributeList(SemaRef.TUScope, Param,
ArgInfo[i].ArgAttrs);
SemaRef.AddPragmaAttributes(SemaRef.TUScope, Param);
for (unsigned I = 0; I < Sel.getNumArgs(); ++I) {
ParmVarDecl *Param = ArgInfo[I];
Param->setDeclContext(ObjCMethod);
SemaRef.ProcessAPINotes(Param);

if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
Param->setInvalidDecl();
}
S->AddDecl(Param);
SemaRef.IdResolver.AddDecl(Param);

Params.push_back(Param);
}

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8757,8 +8757,7 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin,
ResTy = ResTy.getSingleStepDesugaredType(Ctx);

// Create a new AttributedType with the new nullability kind.
auto NewAttr = AttributedType::getNullabilityAttrKind(MergedKind);
return Ctx.getAttributedType(NewAttr, ResTy, ResTy);
return Ctx.getAttributedType(MergedKind, ResTy, ResTy);
}

ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
Expand Down
29 changes: 9 additions & 20 deletions clang/lib/Sema/SemaExprObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,9 +551,7 @@ ExprResult SemaObjC::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
const llvm::UTF8 *StrEnd = Str.bytes_end();
// Check that this is a valid UTF-8 string.
if (llvm::isLegalUTF8String(&StrBegin, StrEnd)) {
BoxedType = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(
NullabilityKind::NonNull),
BoxedType = Context.getAttributedType(NullabilityKind::NonNull,
NSStringPointer, NSStringPointer);
return new (Context) ObjCBoxedExpr(CE, BoxedType, nullptr, SR);
}
Expand Down Expand Up @@ -605,9 +603,8 @@ ExprResult SemaObjC::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) {
std::optional<NullabilityKind> Nullability =
BoxingMethod->getReturnType()->getNullability();
if (Nullability)
BoxedType = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability), BoxedType,
BoxedType);
BoxedType =
Context.getAttributedType(*Nullability, BoxedType, BoxedType);
}
} else if (ValueType->isBuiltinType()) {
// The other types we support are numeric, char and BOOL/bool. We could also
Expand Down Expand Up @@ -1444,10 +1441,8 @@ static QualType stripObjCInstanceType(ASTContext &Context, QualType T) {
QualType origType = T;
if (auto nullability = AttributedType::stripOuterNullability(T)) {
if (T == Context.getObjCInstanceType()) {
return Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*nullability),
Context.getObjCIdType(),
Context.getObjCIdType());
return Context.getAttributedType(*nullability, Context.getObjCIdType(),
Context.getObjCIdType());
}

return origType;
Expand Down Expand Up @@ -1485,10 +1480,7 @@ static QualType getBaseMessageSendResultType(Sema &S,
(void)AttributedType::stripOuterNullability(type);

// Form a new attributed type using the method result type's nullability.
return Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*nullability),
type,
type);
return Context.getAttributedType(*nullability, type, type);
}

return type;
Expand Down Expand Up @@ -1559,9 +1551,8 @@ QualType SemaObjC::getMessageSendResultType(const Expr *Receiver,
QualType NewResultType = Context.getObjCObjectPointerType(
Context.getObjCInterfaceType(MD->getClassInterface()));
if (auto Nullability = resultType->getNullability())
NewResultType = Context.getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability),
NewResultType, NewResultType);
NewResultType = Context.getAttributedType(*Nullability, NewResultType,
NewResultType);
return NewResultType;
}
}
Expand Down Expand Up @@ -1623,9 +1614,7 @@ QualType SemaObjC::getMessageSendResultType(const Expr *Receiver,
if (newResultNullabilityIdx > 0) {
auto newNullability
= static_cast<NullabilityKind>(newResultNullabilityIdx-1);
return Context.getAttributedType(
AttributedType::getNullabilityAttrKind(newNullability),
resultType, resultType);
return Context.getAttributedType(newNullability, resultType, resultType);
}

return resultType;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaObjCProperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2460,7 +2460,7 @@ void SemaObjC::ProcessPropertyDecl(ObjCPropertyDecl *property) {
QualType modifiedTy = resultTy;
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) {
if (*nullability == NullabilityKind::Unspecified)
resultTy = Context.getAttributedType(attr::TypeNonNull,
resultTy = Context.getAttributedType(NullabilityKind::NonNull,
modifiedTy, modifiedTy);
}
}
Expand Down Expand Up @@ -2538,7 +2538,7 @@ void SemaObjC::ProcessPropertyDecl(ObjCPropertyDecl *property) {
QualType modifiedTy = paramTy;
if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){
if (*nullability == NullabilityKind::Unspecified)
paramTy = Context.getAttributedType(attr::TypeNullable,
paramTy = Context.getAttributedType(NullabilityKind::Nullable,
modifiedTy, modifiedTy);
}
}
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Sema/SemaSwift.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,16 @@ static bool isValidSwiftErrorResultType(QualType Ty) {
}

void SemaSwift::handleAttrAttr(Decl *D, const ParsedAttr &AL) {
if (AL.isInvalid() || AL.isUsedAsTypeAttr())
return;

// Make sure that there is a string literal as the annotation's single
// argument.
StringRef Str;
if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str))
if (!SemaRef.checkStringLiteralArgumentAttr(AL, 0, Str)) {
AL.setInvalid();
return;
}

D->addAttr(::new (getASTContext()) SwiftAttrAttr(getASTContext(), AL, Str));
}
Expand Down
67 changes: 63 additions & 4 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ namespace {
QualType getAttributedType(Attr *A, QualType ModifiedType,
QualType EquivType) {
QualType T =
sema.Context.getAttributedType(A->getKind(), ModifiedType, EquivType);
sema.Context.getAttributedType(A, ModifiedType, EquivType);
AttrsForTypes.push_back({cast<AttributedType>(T.getTypePtr()), A});
AttrsForTypesSorted = false;
return T;
Expand Down Expand Up @@ -7161,6 +7161,60 @@ static bool HandleWebAssemblyFuncrefAttr(TypeProcessingState &State,
return false;
}

static void HandleSwiftAttr(TypeProcessingState &State, TypeAttrLocation TAL,
QualType &QT, ParsedAttr &PAttr) {
if (TAL == TAL_DeclName)
return;

Sema &S = State.getSema();
auto &D = State.getDeclarator();

// If the attribute appears in declaration specifiers
// it should be handled as a declaration attribute,
// unless it's associated with a type or a function
// prototype (i.e. appears on a parameter or result type).
if (State.isProcessingDeclSpec()) {
if (!(D.isPrototypeContext() ||
D.getContext() == DeclaratorContext::TypeName))
return;

if (auto *chunk = D.getInnermostNonParenChunk()) {
moveAttrFromListToList(PAttr, State.getCurrentAttributes(),
const_cast<DeclaratorChunk *>(chunk)->getAttrs());
return;
}
}

StringRef Str;
if (!S.checkStringLiteralArgumentAttr(PAttr, 0, Str)) {
PAttr.setInvalid();
return;
}

// If the attribute as attached to a paren move it closer to
// the declarator. This can happen in block declarations when
// an attribute is placed before `^` i.e. `(__attribute__((...)) ^)`.
//
// Note that it's actually invalid to use GNU style attributes
// in a block but such cases are currently handled gracefully
// but the parser and behavior should be consistent between
// cases when attribute appears before/after block's result
// type and inside (^).
if (TAL == TAL_DeclChunk) {
auto chunkIdx = State.getCurrentChunkIndex();
if (chunkIdx >= 1 &&
D.getTypeObject(chunkIdx).Kind == DeclaratorChunk::Paren) {
moveAttrFromListToList(PAttr, State.getCurrentAttributes(),
D.getTypeObject(chunkIdx - 1).getAttrs());
return;
}
}

auto *A = ::new (S.Context) SwiftAttrAttr(S.Context, PAttr, Str);
QT = State.getAttributedType(A, QT, QT);
PAttr.setUsedAsTypeAttr();
}

/// Rebuild an attributed type without the nullability attribute on it.
static QualType rebuildAttributedTypeWithoutNullability(ASTContext &Ctx,
QualType Type) {
Expand All @@ -7177,7 +7231,8 @@ static QualType rebuildAttributedTypeWithoutNullability(ASTContext &Ctx,
Ctx, Attributed->getModifiedType());
assert(Modified.getTypePtr() != Attributed->getModifiedType().getTypePtr());
return Ctx.getAttributedType(Attributed->getAttrKind(), Modified,
Attributed->getEquivalentType());
Attributed->getEquivalentType(),
Attributed->getAttr());
}

/// Map a nullability attribute kind to a nullability kind.
Expand Down Expand Up @@ -7306,8 +7361,7 @@ static bool CheckNullabilityTypeSpecifier(
Attr *A = createNullabilityAttr(S.Context, *PAttr, Nullability);
QT = State->getAttributedType(A, QT, QT);
} else {
attr::Kind attrKind = AttributedType::getNullabilityAttrKind(Nullability);
QT = S.Context.getAttributedType(attrKind, QT, QT);
QT = S.Context.getAttributedType(Nullability, QT, QT);
}
return false;
}
Expand Down Expand Up @@ -8749,6 +8803,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
break;
}

case ParsedAttr::AT_SwiftAttr: {
HandleSwiftAttr(state, TAL, type, attr);
break;
}

MS_TYPE_ATTRS_CASELIST:
if (!handleMSPointerTypeQualifierAttr(state, attr, type))
attr.setUsedAsTypeAttr();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaX86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ bool SemaX86::CheckBuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_tdpfp16ps:
case X86::BI__builtin_ia32_tcmmimfp16ps:
case X86::BI__builtin_ia32_tcmmrlfp16ps:
case X86::BI__builtin_ia32_tdpbf8ps:
case X86::BI__builtin_ia32_tdpbhf8ps:
case X86::BI__builtin_ia32_tdphbf8ps:
case X86::BI__builtin_ia32_tdphf8ps:
return CheckBuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2});
}
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -7435,7 +7435,8 @@ QualType TreeTransform<Derived>::TransformAttributedType(TypeLocBuilder &TLB,

result = SemaRef.Context.getAttributedType(TL.getAttrKind(),
modifiedType,
equivalentType);
equivalentType,
TL.getAttr());
}

AttributedTypeLoc newTL = TLB.push<AttributedTypeLoc>(result);
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -860,11 +860,12 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// If one of the operands is a symbol and the other is a constant,
// build an expression for use by the constraint manager.
if (SymbolRef rSym = rhs.getAsLocSymbol()) {
// We can only build expressions with symbols on the left,
// so we need a reversible operator.
if (!BinaryOperator::isComparisonOp(op) || op == BO_Cmp)
if (op == BO_Cmp)
return UnknownVal();

if (!BinaryOperator::isComparisonOp(op))
return makeNonLoc(L.getValue(), op, rSym, resultTy);

op = BinaryOperator::reverseComparisonOp(op);
return makeNonLoc(rSym, op, L.getValue(), resultTy);
}
Expand Down
19 changes: 19 additions & 0 deletions clang/test/AST/ByteCode/new-delete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ namespace NowThrowNew {
static_assert(erroneous_array_bound_nothrow2(-1) == 0);// expected-error {{not an integral constant expression}}
static_assert(!erroneous_array_bound_nothrow2(1LL << 62));// expected-error {{not an integral constant expression}}

constexpr bool erroneous_array_bound(long long n) {
delete[] new int[n]; // both-note {{array bound -1 is negative}} both-note {{array bound 4611686018427387904 is too large}}
return true;
}
static_assert(erroneous_array_bound(3));
static_assert(erroneous_array_bound(0));
static_assert(erroneous_array_bound(-1)); // both-error {{constant expression}} both-note {{in call}}
static_assert(erroneous_array_bound(1LL << 62)); // both-error {{constant expression}} both-note {{in call}}

constexpr bool evaluate_nothrow_arg() {
bool ok = false;
delete new ((ok = true, std::nothrow)) int;
Expand Down Expand Up @@ -569,6 +578,16 @@ namespace CastedDelete {
return a;
}
static_assert(vdtor_1() == 1);

constexpr int foo() { // both-error {{never produces a constant expression}}
struct S {};
struct T : S {};
S *p = new T();
delete p; // both-note 2{{delete of object with dynamic type 'T' through pointer to base class type 'S' with non-virtual destructor}}
return 1;
}
static_assert(foo() == 1); // both-error {{not an integral constant expression}} \
// both-note {{in call to}}
}

constexpr void use_after_free_2() { // both-error {{never produces a constant expression}}
Expand Down
47 changes: 46 additions & 1 deletion clang/test/AST/attr-swift_attr.m
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
// RUN: %clang_cc1 -fblocks -ast-dump %s | FileCheck %s

__attribute__((swift_attr("@actor")))
@interface View
Expand All @@ -14,3 +14,48 @@ @interface Contact

// CHECK-LABEL: InterfaceDecl {{.*}} Contact
// CHECK-NEXT: SwiftAttrAttr {{.*}} "@sendable"

#define SWIFT_SENDABLE __attribute__((swift_attr("@Sendable")))

@interface InTypeContext
- (nullable id)test:(nullable SWIFT_SENDABLE id)obj SWIFT_SENDABLE;
@end

// CHECK-LABEL: InterfaceDecl {{.*}} InTypeContext
// CHECK-NEXT: MethodDecl {{.*}} - test: 'id _Nullable':'id'
// CHECK-NEXT: ParmVarDecl {{.*}} obj 'SWIFT_SENDABLE id _Nullable':'id'
// CHECK-NEXT: SwiftAttrAttr {{.*}} "@Sendable"

@interface Generic<T: SWIFT_SENDABLE id>
@end

// CHECK-LABEL: InterfaceDecl {{.*}} Generic
// CHECK-NEXT: TypeParamDecl {{.*}} T bounded 'SWIFT_SENDABLE id':'id'

typedef SWIFT_SENDABLE Generic<id> Alias;

// CHECK-LABEL: TypedefDecl {{.*}} Alias 'Generic<id>'
// CHECK-NEXT: ObjectType {{.*}} 'Generic<id>'
// CHECK-NEXT: SwiftAttrAttr {{.*}} "@Sendable"

SWIFT_SENDABLE
typedef struct {
void *ptr;
} SendableStruct;

// CHECK-LABEL: TypedefDecl {{.*}} SendableStruct 'struct SendableStruct':'SendableStruct'
// CHECK: SwiftAttrAttr {{.*}} "@Sendable"

@interface TestAttrPlacementInBlock1
-(void) withHandler: (void (SWIFT_SENDABLE ^)(id)) handler;
@end

// CHECK-LABEL: ObjCInterfaceDecl {{.*}} TestAttrPlacementInBlock1
// CHECK: handler 'SWIFT_SENDABLE void (^)(id)':'void (^)(id)'

@interface TestAttrPlacementInBlock2
-(void) withHandler: (void (^ SWIFT_SENDABLE)(id)) handler;
@end

// CHECK-LABEL: ObjCInterfaceDecl {{.*}} TestAttrPlacementInBlock2
// CHECK: handler 'SWIFT_SENDABLE void (^)(id)':'void (^)(id)'
27 changes: 27 additions & 0 deletions clang/test/CodeGen/X86/amx_fp8.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown -target-feature +amx-fp8 \
// RUN: -emit-llvm -o - -Werror -pedantic | FileCheck %s
#include <immintrin.h>

void test_amx(void *data) {
//CHECK-LABEL: @test_amx
//CHECK: call void @llvm.x86.tdpbf8ps(i8 1, i8 2, i8 3)
_tile_dpbf8ps(1, 2, 3);
}

void test_amx2(void *data) {
//CHECK-LABEL: @test_amx2
//CHECK: call void @llvm.x86.tdpbhf8ps(i8 1, i8 2, i8 3)
_tile_dpbhf8ps(1, 2, 3);
}

void test_amx3(void *data) {
//CHECK-LABEL: @test_amx3
//CHECK: call void @llvm.x86.tdphbf8ps(i8 1, i8 2, i8 3)
_tile_dphbf8ps(1, 2, 3);
}

void test_amx4(void *data) {
//CHECK-LABEL: @test_amx4
//CHECK: call void @llvm.x86.tdphf8ps(i8 1, i8 2, i8 3)
_tile_dphf8ps(1, 2, 3);
}
10 changes: 10 additions & 0 deletions clang/test/CodeGen/X86/amx_fp8_errors.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown -target-feature +amx-tile -target-feature +amx-fp8 -verify

#include <immintrin.h>

void test_amx(void *data) {
_tile_dpbf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}}
_tile_dpbhf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}}
_tile_dphbf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}}
_tile_dphf8ps(4, 3, 3); // expected-error {{tile arguments must refer to different tiles}}
}
32 changes: 32 additions & 0 deletions clang/test/CodeGen/X86/amx_fp8_inline_asm.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-unknown-unknown -target-feature +amx-fp8 -emit-llvm -o - -Wall -Werror -pedantic | FileCheck %s

void f_tilemul(short a)
{
//CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdpbf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"()
__asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t"
"tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t"
"tdpbf8ps %%tmm6, %%tmm0, %%tmm7 \n\t"
"tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t"
::: "memory", "tmm0", "tmm6", "tmm7");

//CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdpbhf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"()
__asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t"
"tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t"
"tdpbhf8ps %%tmm6, %%tmm0, %%tmm7 \n\t"
"tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t"
::: "memory", "tmm0", "tmm6", "tmm7");

//CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdphbf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"()
__asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t"
"tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t"
"tdphbf8ps %%tmm6, %%tmm0, %%tmm7 \n\t"
"tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t"
::: "memory", "tmm0", "tmm6", "tmm7");

//CHECK: call void asm sideeffect "tileloadd 0(%rsi,%r13,4), %tmm0 \0A\09tileloadd 0(%rdx,%r14,4), %tmm6 \0A\09tdphf8ps %tmm6, %tmm0, %tmm7 \0A\09tilestored %tmm7, 0(%r12,%r15,4) \0A\09", "~{memory},~{tmm0},~{tmm6},~{tmm7},~{dirflag},~{fpsr},~{flags}"()
__asm__ volatile ("tileloadd 0(%%rsi,%%r13,4), %%tmm0 \n\t"
"tileloadd 0(%%rdx,%%r14,4), %%tmm6 \n\t"
"tdphf8ps %%tmm6, %%tmm0, %%tmm7 \n\t"
"tilestored %%tmm7, 0(%%r12,%%r15,4) \n\t"
::: "memory", "tmm0", "tmm6", "tmm7");
}
19 changes: 0 additions & 19 deletions clang/test/CodeGen/pgo-cold-function-coverage.c

This file was deleted.

60 changes: 57 additions & 3 deletions clang/test/CodeGenOpenCL/builtins-amdgcn-gfx10.cl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// RUN: %clang_cc1 -triple amdgcn-unknown-unknown -target-cpu gfx1012 -emit-llvm -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple spirv64-amd-amdhsa -emit-llvm -o - %s | FileCheck %s

#pragma OPENCL EXTENSION cl_khr_fp16 : enable

typedef unsigned int uint;
typedef unsigned long ulong;

Expand All @@ -19,12 +21,64 @@ void test_permlanex16(global uint* out, uint a, uint b, uint c, uint d) {
*out = __builtin_amdgcn_permlanex16(a, b, c, d, 0, 0);
}

// CHECK-LABEL: @test_mov_dpp8(
// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.mov.dpp8.i32(i32 %a, i32 1)
void test_mov_dpp8(global uint* out, uint a) {
// CHECK-LABEL: @test_mov_dpp8_uint(
// CHECK: {{.*}}call{{.*}} i32 @llvm.amdgcn.mov.dpp8.i32(i32 %a, i32 1)
// CHECK-NEXT: store i32 %0,
void test_mov_dpp8_uint(global uint* out, uint a) {
*out = __builtin_amdgcn_mov_dpp8(a, 1);
}

// CHECK-LABEL: @test_mov_dpp8_long(
// CHECK: {{.*}}call{{.*}} i64 @llvm.amdgcn.mov.dpp8.i64(i64 %a, i32 1)
// CHECK-NEXT: store i64 %0,
void test_mov_dpp8_long(global long* out, long a) {
*out = __builtin_amdgcn_mov_dpp8(a, 1);
}

// CHECK-LABEL: @test_mov_dpp8_float(
// CHECK: %0 = bitcast float %a to i32
// CHECK-NEXT: %1 = tail call{{.*}} i32 @llvm.amdgcn.mov.dpp8.i32(i32 %0, i32 1)
// CHECK-NEXT: store i32 %1,
void test_mov_dpp8_float(global float* out, float a) {
*out = __builtin_amdgcn_mov_dpp8(a, 1);
}

// CHECK-LABEL: @test_mov_dpp8_double
// CHECK: %0 = bitcast double %x to i64
// CHECK-NEXT: %1 = tail call{{.*}} i64 @llvm.amdgcn.mov.dpp8.i64(i64 %0, i32 1)
// CHECK-NEXT: store i64 %1,
void test_mov_dpp8_double(double x, global double *p) {
*p = __builtin_amdgcn_mov_dpp8(x, 1);
}

// CHECK-LABEL: @test_mov_dpp8_short
// CHECK: %0 = zext i16 %x to i32
// CHECK-NEXT: %1 = tail call{{.*}} i32 @llvm.amdgcn.mov.dpp8.i32(i32 %0, i32 1)
// CHECK-NEXT: %2 = trunc i32 %1 to i16
// CHECK-NEXT: store i16 %2,
void test_mov_dpp8_short(short x, global short *p) {
*p = __builtin_amdgcn_mov_dpp8(x, 1);
}

// CHECK-LABEL: @test_mov_dpp8_char
// CHECK: %0 = zext i8 %x to i32
// CHECK-NEXT: %1 = tail call{{.*}} i32 @llvm.amdgcn.mov.dpp8.i32(i32 %0, i32 1)
// CHECK-NEXT: %2 = trunc i32 %1 to i8
// CHECK-NEXT: store i8 %2,
void test_mov_dpp8_char(char x, global char *p) {
*p = __builtin_amdgcn_mov_dpp8(x, 1);
}

// CHECK-LABEL: @test_mov_dpp8_half
// CHECK: %0 = load i16,
// CHECK: %1 = zext i16 %0 to i32
// CHECK-NEXT: %2 = tail call{{.*}} i32 @llvm.amdgcn.mov.dpp8.i32(i32 %1, i32 1)
// CHECK-NEXT: %3 = trunc i32 %2 to i16
// CHECK-NEXT: store i16 %3,
void test_mov_dpp8_half(half *x, global half *p) {
*p = __builtin_amdgcn_mov_dpp8(*x, 1);
}

// CHECK-LABEL: @test_s_memtime
// CHECK: {{.*}}call{{.*}} i64 @llvm.amdgcn.s.memtime()
void test_s_memtime(global ulong* out)
Expand Down
8 changes: 0 additions & 8 deletions clang/test/Driver/fprofile-generate-cold-function-coverage.c

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm -fretain-comments-from-system-headers
// RUN: %clang_cc1 -std=c++20 %t/b.cpp -fmodule-file=a=%t/a.pcm -verify -fsyntax-only

//--- a.cppm
export module a;

//--- b.cpp
// expected-no-diagnostics
import a;
4 changes: 4 additions & 0 deletions clang/test/SemaObjC/validate-attr-swift_attr.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ @interface I
__attribute__((swift_attr(1)))
@interface J
@end

@interface Error<T: __attribute__((swift_attr(1))) id>
// expected-error@-1 {{expected string literal as argument of 'swift_attr' attribute}}
@end
19 changes: 19 additions & 0 deletions clang/test/SemaOpenCL/builtins-amdgcn-error-gfx10.cl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,30 @@
// RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx900 -verify -S -o - %s
// RUN: %clang_cc1 -triple amdgcn-- -target-cpu gfx908 -verify -S -o - %s

#pragma OPENCL EXTENSION cl_khr_fp16 : enable

typedef unsigned int uint;
typedef int int2 __attribute__((ext_vector_type(2)));

struct S {
int x;
};

void test(global uint* out, uint a, uint b, uint c, uint d) {
*out = __builtin_amdgcn_permlane16(a, b, c, d, 1, 1); // expected-error {{'__builtin_amdgcn_permlane16' needs target feature gfx10-insts}}
*out = __builtin_amdgcn_permlanex16(a, b, c, d, 1, 1); // expected-error {{'__builtin_amdgcn_permlanex16' needs target feature gfx10-insts}}
*out = __builtin_amdgcn_mov_dpp8(a, 1); // expected-error {{'__builtin_amdgcn_mov_dpp8' needs target feature gfx10-insts}}
}

void test_mov_dpp8(global int* out, int src, int i, int2 i2, struct S s, float _Complex fc)
{
*out = __builtin_amdgcn_mov_dpp8(src, i); // expected-error{{argument to '__builtin_amdgcn_mov_dpp8' must be a constant integer}}
*out = __builtin_amdgcn_mov_dpp8(src, 0.1); // expected-error{{argument to '__builtin_amdgcn_mov_dpp8' must be a constant integer}}
*out = __builtin_amdgcn_mov_dpp8(src); // expected-error{{too few arguments to function call, expected 2, have 1}}
*out = __builtin_amdgcn_mov_dpp8(src, 0, 0); // expected-error{{too many arguments to function call, expected at most 2, have 3}}
*out = __builtin_amdgcn_mov_dpp8(out, 0); // expected-error{{used type '__global int *__private' where integer or floating point type is required}}
*out = __builtin_amdgcn_mov_dpp8("aa", 0); // expected-error{{used type '__constant char[3]' where integer or floating point type is required}}
*out = __builtin_amdgcn_mov_dpp8(i2, 0); // expected-error{{used type '__private int2' (vector of 2 'int' values) where integer or floating point type is required}}
*out = __builtin_amdgcn_mov_dpp8(s, 0); // expected-error{{used type '__private struct S' where integer or floating point type is required}}
*out = __builtin_amdgcn_mov_dpp8(fc, 0); // expected-error{{used type '__private _Complex float' where integer or floating point type is required}}
}
45 changes: 0 additions & 45 deletions clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,33 +216,6 @@ void printCommands(ArrayRef<StringRef> CmdArgs) {
exit(EXIT_FAILURE);
}

/// Create an extra user-specified \p OffloadFile.
/// TODO: We should find a way to wrap these as libraries instead.
Expected<OffloadFile> getInputBitcodeLibrary(StringRef Input) {
auto [Device, Path] = StringRef(Input).split('=');
auto [String, Arch] = Device.rsplit('-');
auto [Kind, Triple] = String.split('-');

llvm::ErrorOr<std::unique_ptr<MemoryBuffer>> ImageOrError =
llvm::MemoryBuffer::getFileOrSTDIN(Path);
if (std::error_code EC = ImageOrError.getError())
return createFileError(Path, EC);

OffloadingImage Image{};
Image.TheImageKind = IMG_Bitcode;
Image.TheOffloadKind = getOffloadKind(Kind);
Image.StringData["triple"] = Triple;
Image.StringData["arch"] = Arch;
Image.Image = std::move(*ImageOrError);

std::unique_ptr<MemoryBuffer> Binary =
MemoryBuffer::getMemBufferCopy(OffloadBinary::write(Image));
auto NewBinaryOrErr = OffloadBinary::create(*Binary);
if (!NewBinaryOrErr)
return NewBinaryOrErr.takeError();
return OffloadFile(std::move(*NewBinaryOrErr), std::move(Binary));
}

std::string getMainExecutable(const char *Name) {
void *Ptr = (void *)(intptr_t)&getMainExecutable;
auto COWPath = sys::fs::getMainExecutable(Name, Ptr);
Expand Down Expand Up @@ -600,17 +573,6 @@ Expected<StringRef> clang(ArrayRef<StringRef> InputFiles, const ArgList &Args) {
for (StringRef Arg : Args.getAllArgValues(OPT_compiler_arg_EQ))
CmdArgs.push_back(Args.MakeArgString(Arg));

for (StringRef Arg : Args.getAllArgValues(OPT_builtin_bitcode_EQ)) {
if (llvm::Triple(Arg.split('=').first) == Triple)
CmdArgs.append({"-Xclang", "-mlink-builtin-bitcode", "-Xclang",
Args.MakeArgString(Arg.split('=').second)});
}

// The OpenMPOpt pass can introduce new calls and is expensive, we do
// not want this when running CodeGen through clang.
if (Args.hasArg(OPT_clang_backend) || Args.hasArg(OPT_builtin_bitcode_EQ))
CmdArgs.append({"-mllvm", "-openmp-opt-disable"});

if (Error Err = executeCommands(*ClangPath, CmdArgs))
return std::move(Err);

Expand Down Expand Up @@ -1362,13 +1324,6 @@ getDeviceInput(const ArgList &Args) {
}
}

for (StringRef Library : Args.getAllArgValues(OPT_bitcode_library_EQ)) {
auto FileOrErr = getInputBitcodeLibrary(Library);
if (!FileOrErr)
return FileOrErr.takeError();
InputFiles[*FileOrErr].push_back(std::move(*FileOrErr));
}

SmallVector<SmallVector<OffloadFile>> InputsForTarget;
for (auto &[ID, Input] : InputFiles)
InputsForTarget.emplace_back(std::move(Input));
Expand Down
10 changes: 0 additions & 10 deletions clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,12 @@ def host_triple_EQ : Joined<["--"], "host-triple=">,
def opt_level : Joined<["--"], "opt-level=">,
Flags<[WrapperOnlyOption]>, MetaVarName<"<O0, O1, O2, or O3>">,
HelpText<"Optimization level for LTO">;
def bitcode_library_EQ : Joined<["--"], "bitcode-library=">,
Flags<[WrapperOnlyOption]>, MetaVarName<"<kind>-<triple>-<arch>=<path>">,
HelpText<"Extra bitcode library to link">;
def builtin_bitcode_EQ : Joined<["--"], "builtin-bitcode=">,
Flags<[WrapperOnlyOption]>, MetaVarName<"<triple>=<path>">,
HelpText<"Perform a special internalizing link on the bitcode file. "
"This is necessary for some vendor libraries to be linked correctly">;
def device_linker_args_EQ : Joined<["--"], "device-linker=">,
Flags<[WrapperOnlyOption]>, MetaVarName<"<value> or <triple>=<value>">,
HelpText<"Arguments to pass to the device linker invocation">;
def device_compiler_args_EQ : Joined<["--"], "device-compiler=">,
Flags<[WrapperOnlyOption]>, MetaVarName<"<value> or <triple>=<value>">,
HelpText<"Arguments to pass to the device compiler invocation">;
def clang_backend : Flag<["--"], "clang-backend">,
Flags<[WrapperOnlyOption]>,
HelpText<"Run the backend using clang rather than the LTO backend">;
def dry_run : Flag<["--"], "dry-run">,
Flags<[WrapperOnlyOption]>,
HelpText<"Print program arguments without running">;
Expand Down
20 changes: 19 additions & 1 deletion clang/unittests/AST/ByteCode/toAPValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ TEST(ToAPValue, Pointers) {
"constexpr S d = {{{true, false}, {false, true}, {false, false}}};\n"
"constexpr const bool *b = &d.a[1].z;\n"
"const void *p = (void*)12;\n"
"const void *nullp = (void*)0;\n";
"const void *nullp = (void*)0;\n"
"extern int earr[5][5];\n"
"constexpr const int *arrp = &earr[2][4];\n";

auto AST = tooling::buildASTFromCodeWithArgs(
Code, {"-fexperimental-new-constant-interpreter"});
Expand Down Expand Up @@ -87,6 +89,22 @@ TEST(ToAPValue, Pointers) {
ASSERT_TRUE(Success);
ASSERT_EQ(I, 0);
}

// A multidimensional array.
{
const ValueDecl *D = getDecl("arrp");
ASSERT_NE(D, nullptr);
const Pointer &GP = getGlobalPtr("arrp").deref<Pointer>();
APValue A = GP.toAPValue(ASTCtx);
ASSERT_TRUE(A.isLValue());
ASSERT_TRUE(A.hasLValuePath());
ASSERT_EQ(A.getLValuePath().size(), 2u);
ASSERT_EQ(A.getLValuePath()[0].getAsArrayIndex(), 2u);
ASSERT_EQ(A.getLValuePath()[1].getAsArrayIndex(), 4u);
ASSERT_EQ(A.getLValueOffset().getQuantity(), 56u);
ASSERT_TRUE(
GP.atIndex(0).getFieldDesc()->getElemQualType()->isIntegerType());
}
}

TEST(ToAPValue, FunctionPointers) {
Expand Down
1 change: 1 addition & 0 deletions clang/unittests/StaticAnalyzer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_clang_unittest(StaticAnalysisTests
RegisterCustomCheckersTest.cpp
StoreTest.cpp
SymbolReaperTest.cpp
SValSimplifyerTest.cpp
SValTest.cpp
TestReturnValueUnderConstruction.cpp
Z3CrosscheckOracleTest.cpp
Expand Down
103 changes: 103 additions & 0 deletions clang/unittests/StaticAnalyzer/SValSimplifyerTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//===- unittests/StaticAnalyzer/SValSimplifyerTest.cpp --------------------===//
//
// 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 "CheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"

using namespace clang;
using namespace ento;

static std::string toString(SVal V) {
std::string Result;
llvm::raw_string_ostream Stream(Result);
V.dumpToStream(Stream);
return Result;
}

static void replace(std::string &Content, StringRef Substr,
StringRef Replacement) {
std::size_t Pos = 0;
while ((Pos = Content.find(Substr, Pos)) != std::string::npos) {
Content.replace(Pos, Substr.size(), Replacement);
Pos += Replacement.size();
}
}

namespace {

class SimplifyChecker : public Checker<check::PreCall> {
const BugType Bug{this, "SimplifyChecker"};
const CallDescription SimplifyCall{CDM::SimpleFunc, {"simplify"}, 1};

void report(CheckerContext &C, const Expr *E, StringRef Description) const {
PathDiagnosticLocation Loc(E->getExprLoc(), C.getSourceManager());
auto Report = std::make_unique<BasicBugReport>(Bug, Description, Loc);
C.emitReport(std::move(Report));
}

public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const {
if (!SimplifyCall.matches(Call))
return;
const Expr *Arg = Call.getArgExpr(0);
SVal Val = C.getSVal(Arg);
SVal SimplifiedVal = C.getSValBuilder().simplifySVal(C.getState(), Val);
std::string Subject = toString(Val);
std::string Simplified = toString(SimplifiedVal);
std::string Message = (llvm::Twine{Subject} + " -> " + Simplified).str();
report(C, Arg, Message);
}
};
} // namespace

static void addSimplifyChecker(AnalysisASTConsumer &AnalysisConsumer,
AnalyzerOptions &AnOpts) {
AnOpts.CheckersAndPackages = {{"SimplifyChecker", true}};
AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) {
Registry.addChecker<SimplifyChecker>("SimplifyChecker", "EmptyDescription",
"EmptyDocsUri");
});
}

static void runThisCheckerOnCode(const std::string &Code, std::string &Diags) {
ASSERT_TRUE(runCheckerOnCode<addSimplifyChecker>(Code, Diags,
/*OnlyEmitWarnings=*/true));
ASSERT_FALSE(Diags.empty());
ASSERT_EQ(Diags.back(), '\n');
Diags.pop_back();
}

namespace {

TEST(SValSimplifyerTest, LHSConstrainedNullPtrDiff) {
constexpr auto Code = R"cpp(
template <class T> void simplify(T);
void LHSConstrainedNullPtrDiff(char *p, char *q) {
int diff = p - q;
if (!p)
simplify(diff);
})cpp";

std::string Diags;
runThisCheckerOnCode(Code, Diags);
replace(Diags, "(reg_$0<char * p>)", "reg_p");
replace(Diags, "(reg_$1<char * q>)", "reg_q");
// This should not be simplified to "Unknown".
EXPECT_EQ(Diags, "SimplifyChecker: reg_p - reg_q -> 0U - reg_q");
}

} // namespace
4 changes: 2 additions & 2 deletions clang/www/OpenProjects.html
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ <h1>Open Clang Projects</h1>
<p>If you hit a bug with Clang, it is very useful for us if you reduce the code
that demonstrates the problem down to something small. There are many ways to
do this; ask on <a href="https://discourse.llvm.org/c/clang">Discourse</a>,
<a href="https://discord.com/channels/636084430946959380/636725486533345280">Discord</a>,
or <a href="https://llvm.org/docs/GettingInvolved.html#irc"IRC</a> for advice.</p>
<a href="https://discord.com/channels/636084430946959380/636725486533345280">Discord</a>
for advice.</p>

</div>
</body>
Expand Down
7 changes: 5 additions & 2 deletions compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,12 @@ INTERCEPTOR(void, free, void *ptr) {
if (DlsymAlloc::PointerIsMine(ptr))
return DlsymAlloc::Free(ptr);

if (ptr != NULL) {
// According to the C and C++ standard, freeing a nullptr is guaranteed to be
// a no-op (and thus real-time safe). This can be confirmed for looking at
// __libc_free in the glibc source.
if (ptr != nullptr)
__rtsan_notify_intercepted_call("free");
}

return REAL(free)(ptr);
}

Expand Down
41 changes: 30 additions & 11 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2131,18 +2131,37 @@ class FirConverter : public Fortran::lower::AbstractConverter {
llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
assert(!incrementLoopNestInfo.empty() && "empty loop nest");
mlir::Location loc = toLocation();
mlir::Operation *boundsAndStepIP = nullptr;

for (IncrementLoopInfo &info : incrementLoopNestInfo) {
info.loopVariable =
genLoopVariableAddress(loc, *info.loopVariableSym, info.isUnordered);
mlir::Value lowerValue = genControlValue(info.lowerExpr, info);
mlir::Value upperValue = genControlValue(info.upperExpr, info);
bool isConst = true;
mlir::Value stepValue = genControlValue(
info.stepExpr, info, info.isStructured() ? nullptr : &isConst);
// Use a temp variable for unstructured loops with non-const step.
if (!isConst) {
info.stepVariable = builder->createTemporary(loc, stepValue.getType());
builder->create<fir::StoreOp>(loc, stepValue, info.stepVariable);
mlir::Value lowerValue;
mlir::Value upperValue;
mlir::Value stepValue;

{
mlir::OpBuilder::InsertionGuard guard(*builder);

// Set the IP before the first loop in the nest so that all nest bounds
// and step values are created outside the nest.
if (boundsAndStepIP)
builder->setInsertionPointAfter(boundsAndStepIP);

info.loopVariable = genLoopVariableAddress(loc, *info.loopVariableSym,
info.isUnordered);
lowerValue = genControlValue(info.lowerExpr, info);
upperValue = genControlValue(info.upperExpr, info);
bool isConst = true;
stepValue = genControlValue(info.stepExpr, info,
info.isStructured() ? nullptr : &isConst);
boundsAndStepIP = stepValue.getDefiningOp();

// Use a temp variable for unstructured loops with non-const step.
if (!isConst) {
info.stepVariable =
builder->createTemporary(loc, stepValue.getType());
boundsAndStepIP =
builder->create<fir::StoreOp>(loc, stepValue, info.stepVariable);
}
}

// Structured loop - generate fir.do_loop.
Expand Down
102 changes: 102 additions & 0 deletions flang/test/Lower/do_concurrent.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s

! Simple tests for structured concurrent loops with loop-control.

pure function bar(n, m)
implicit none
integer, intent(in) :: n, m
integer :: bar
bar = n + m
end function

!CHECK-LABEL: sub1
subroutine sub1(n)
implicit none
integer :: n, m, i, j, k
integer, dimension(n) :: a
!CHECK: %[[LB1:.*]] = arith.constant 1 : i32
!CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index
!CHECK: %[[UB1:.*]] = fir.load %{{.*}}#0 : !fir.ref<i32>
!CHECK: %[[UB1_CVT:.*]] = fir.convert %[[UB1]] : (i32) -> index

!CHECK: %[[LB2:.*]] = arith.constant 1 : i32
!CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> index
!CHECK: %[[UB2:.*]] = fir.call @_QPbar(%{{.*}}, %{{.*}}) proc_attrs<pure> fastmath<contract> : (!fir.ref<i32>, !fir.ref<i32>) -> i32
!CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> index

!CHECK: %[[LB3:.*]] = arith.constant 5 : i32
!CHECK: %[[LB3_CVT:.*]] = fir.convert %[[LB3]] : (i32) -> index
!CHECK: %[[UB3:.*]] = arith.constant 10 : i32
!CHECK: %[[UB3_CVT:.*]] = fir.convert %[[UB3]] : (i32) -> index

!CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered
!CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered
!CHECK: fir.do_loop %{{.*}} = %[[LB3_CVT]] to %[[UB3_CVT]] step %{{.*}} unordered

do concurrent(i=1:n, j=1:bar(n*m, n/m), k=5:10)
a(i) = n
end do
end subroutine

!CHECK-LABEL: sub2
subroutine sub2(n)
implicit none
integer :: n, m, i, j
integer, dimension(n) :: a
!CHECK: %[[LB1:.*]] = arith.constant 1 : i32
!CHECK: %[[LB1_CVT:.*]] = fir.convert %[[LB1]] : (i32) -> index
!CHECK: %[[UB1:.*]] = fir.load %5#0 : !fir.ref<i32>
!CHECK: %[[UB1_CVT:.*]] = fir.convert %[[UB1]] : (i32) -> index
!CHECK: fir.do_loop %{{.*}} = %[[LB1_CVT]] to %[[UB1_CVT]] step %{{.*}} unordered
!CHECK: %[[LB2:.*]] = arith.constant 1 : i32
!CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> index
!CHECK: %[[UB2:.*]] = fir.call @_QPbar(%{{.*}}, %{{.*}}) proc_attrs<pure> fastmath<contract> : (!fir.ref<i32>, !fir.ref<i32>) -> i32
!CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> index
!CHECK: fir.do_loop %{{.*}} = %[[LB2_CVT]] to %[[UB2_CVT]] step %{{.*}} unordered
do concurrent(i=1:n)
do concurrent(j=1:bar(n*m, n/m))
a(i) = n
end do
end do
end subroutine


!CHECK-LABEL: unstructured
subroutine unstructured(inner_step)
integer(4) :: i, j, inner_step

!CHECK-NOT: cf.br
!CHECK-NOT: cf.cond_br
!CHECK: %[[LB1:.*]] = arith.constant 1 : i32
!CHECK: %[[LB1_CVT:.*]] = fir.convert %c1_i32 : (i32) -> i16
!CHECK: %[[UB1:.*]] = arith.constant 5 : i32
!CHECK: %[[UB1_CVT:.*]] = fir.convert %c5_i32 : (i32) -> i16
!CHECK: %[[STP1:.*]] = arith.constant 1 : i16

!CHECK-NOT: cf.br
!CHECK-NOT: cf.cond_br
!CHECK: %[[LB2:.*]] = arith.constant 3 : i32
!CHECK: %[[LB2_CVT:.*]] = fir.convert %[[LB2]] : (i32) -> i16
!CHECK: %[[UB2:.*]] = arith.constant 9 : i32
!CHECK: %[[UB2_CVT:.*]] = fir.convert %[[UB2]] : (i32) -> i16
!CHECK: %[[STP2:.*]] = fir.load %{{.*}}#0 : !fir.ref<i32>
!CHECK: %[[STP2_CVT:.*]] = fir.convert %[[STP2]] : (i32) -> i16
!CHECK: fir.store %[[STP2_CVT]] to %{{.*}} : !fir.ref<i16>
!CHECK: cf.br ^[[I_LOOP_HEADER:.*]]

!CHECK: ^[[I_LOOP_HEADER]]:
!CHECK-NEXT: %{{.*}} = fir.load %{{.*}} : !fir.ref<i16>
!CHECK-NEXT: %{{.*}} = arith.constant 0 : i16
!CHECK-NEXT: %{{.*}} = arith.cmpi sgt, %{{.*}}, %{{.*}}: i16
!CHECK-NEXT: cf.cond_br %{{.*}}, ^[[J_LOOP_HEADER:.*]], ^{{.*}}

!CHECK: ^[[J_LOOP_HEADER]]:
!CHECK-NEXT: %[[RANGE:.*]] = arith.subi %[[UB2_CVT]], %[[LB2_CVT]] : i16
!CHECK-NEXT: %{{.*}} = arith.addi %[[RANGE]], %[[STP2_CVT]] : i16
!CHECK-NEXT: %{{.*}} = arith.divsi %{{.*}}, %[[STP2_CVT]] : i16
do concurrent (integer(2)::i=1:5, j=3:9:inner_step, i.ne.3)
goto (7, 7) i+1
print*, 'E:', i, j
7 continue
enddo
end subroutine unstructured
6 changes: 4 additions & 2 deletions libc/src/string/string_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,13 @@ LIBC_INLINE constexpr static char *strrchr_implementation(const char *src,
int c) {
char ch = static_cast<char>(c);
char *last_occurrence = nullptr;
for (; *src; ++src) {
while (true) {
if (*src == ch)
last_occurrence = const_cast<char *>(src);
if (!*src)
return last_occurrence;
++src;
}
return last_occurrence;
}

} // namespace internal
Expand Down
8 changes: 8 additions & 0 deletions libc/test/UnitTest/LibcTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ class Test {
(unsigned long long)RHS, LHSStr, RHSStr, Loc);
}

// Helper to allow macro invocations like `ASSERT_EQ(foo, nullptr)`.
template <typename ValType,
cpp::enable_if_t<cpp::is_pointer_v<ValType>, ValType> = nullptr>
bool test(TestCond Cond, ValType LHS, cpp::nullptr_t, const char *LHSStr,
const char *RHSStr, internal::Location Loc) {
return test(Cond, LHS, static_cast<ValType>(nullptr), LHSStr, RHSStr, Loc);
}

template <
typename ValType,
cpp::enable_if_t<
Expand Down
36 changes: 22 additions & 14 deletions libc/test/src/string/StrchrTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ template <auto Func> struct StrchrTest : public LIBC_NAMESPACE::testing::Test {
const char *src = "abcde";

// Should return null terminator.
ASSERT_STREQ(Func(src, '\0'), "");
const char *nul_terminator = Func(src, '\0');
ASSERT_NE(nul_terminator, nullptr);
ASSERT_STREQ(nul_terminator, "");
// Source string should not change.
ASSERT_STREQ(src, "abcde");
}

void characterNotWithinStringShouldReturnNullptr() {
// Since 'z' is not within the string, should return nullptr.
ASSERT_STREQ(Func("123?", 'z'), nullptr);
ASSERT_EQ(Func("123?", 'z'), nullptr);
}

void theSourceShouldNotChange() {
Expand All @@ -74,11 +76,13 @@ template <auto Func> struct StrchrTest : public LIBC_NAMESPACE::testing::Test {

void emptyStringShouldOnlyMatchNullTerminator() {
// Null terminator should match.
ASSERT_STREQ(Func("", '\0'), "");
const char empty_string[] = "";
ASSERT_EQ(static_cast<const char *>(Func(empty_string, '\0')),
empty_string);
// All other characters should not match.
ASSERT_STREQ(Func("", 'Z'), nullptr);
ASSERT_STREQ(Func("", '3'), nullptr);
ASSERT_STREQ(Func("", '*'), nullptr);
ASSERT_EQ(Func("", 'Z'), nullptr);
ASSERT_EQ(Func("", '3'), nullptr);
ASSERT_EQ(Func("", '*'), nullptr);
}
};

Expand Down Expand Up @@ -114,25 +118,27 @@ template <auto Func> struct StrrchrTest : public LIBC_NAMESPACE::testing::Test {
const char *src = "abcde";

// Should return null terminator.
ASSERT_STREQ(Func(src, '\0'), "");
const char *nul_terminator = Func(src, '\0');
ASSERT_NE(nul_terminator, nullptr);
ASSERT_STREQ(nul_terminator, "");
// Source string should not change.
ASSERT_STREQ(src, "abcde");
}

void findsLastBehindFirstNullTerminator() {
static const char src[6] = {'a', 'a', '\0', 'b', '\0', 'c'};
// 'b' is behind a null terminator, so should not be found.
ASSERT_STREQ(Func(src, 'b'), nullptr);
ASSERT_EQ(Func(src, 'b'), nullptr);
// Same goes for 'c'.
ASSERT_STREQ(Func(src, 'c'), nullptr);
ASSERT_EQ(Func(src, 'c'), nullptr);

// Should find the second of the two a's.
ASSERT_STREQ(Func(src, 'a'), "a");
}

void characterNotWithinStringShouldReturnNullptr() {
// Since 'z' is not within the string, should return nullptr.
ASSERT_STREQ(Func("123?", 'z'), nullptr);
ASSERT_EQ(Func("123?", 'z'), nullptr);
}

void shouldFindLastOfDuplicates() {
Expand All @@ -146,11 +152,13 @@ template <auto Func> struct StrrchrTest : public LIBC_NAMESPACE::testing::Test {

void emptyStringShouldOnlyMatchNullTerminator() {
// Null terminator should match.
ASSERT_STREQ(Func("", '\0'), "");
const char empty_string[] = "";
ASSERT_EQ(static_cast<const char *>(Func(empty_string, '\0')),
empty_string);
// All other characters should not match.
ASSERT_STREQ(Func("", 'A'), nullptr);
ASSERT_STREQ(Func("", '2'), nullptr);
ASSERT_STREQ(Func("", '*'), nullptr);
ASSERT_EQ(Func("", 'A'), nullptr);
ASSERT_EQ(Func("", '2'), nullptr);
ASSERT_EQ(Func("", '*'), nullptr);
}
};

Expand Down
6 changes: 4 additions & 2 deletions libc/test/src/sys/statvfs/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ add_libc_unittest(
statvfs_test.cpp
DEPENDS
libc.src.errno.errno
libc.src.sys.statvfs.linux.statfs_utils
libc.src.sys.statvfs.statvfs
libc.src.sys.stat.mkdirat
libc.src.sys.stat.rmdir
libc.test.UnitTest.ErrnoSetterMatcher
)

Expand All @@ -21,8 +22,9 @@ add_libc_unittest(
fstatvfs_test.cpp
DEPENDS
libc.src.errno.errno
libc.src.sys.statvfs.linux.statfs_utils
libc.src.sys.statvfs.fstatvfs
libc.src.sys.stat.mkdirat
libc.src.sys.stat.rmdir
libc.src.fcntl.open
libc.src.unistd.close
libc.test.UnitTest.ErrnoSetterMatcher
Expand Down
81 changes: 44 additions & 37 deletions libc/test/src/sys/statvfs/linux/fstatvfs_test.cpp
Original file line number Diff line number Diff line change
@@ -1,49 +1,56 @@
//===-- Unittests for fstatvfs --------------------------------------------===//
//
// 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 "hdr/fcntl_macros.h"
#include "src/__support/macros/config.h"
#include "src/fcntl/open.h"
#include "src/sys/stat/mkdirat.h"
#include "src/sys/statvfs/fstatvfs.h"
#include "src/sys/statvfs/linux/statfs_utils.h"
#include "src/unistd/close.h"
#include "src/unistd/rmdir.h"
#include "test/UnitTest/ErrnoSetterMatcher.h"
#include "test/UnitTest/LibcTest.h"
#include <linux/magic.h>
#include "test/UnitTest/Test.h"

using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;

#ifdef SYS_statfs64
using StatFs = statfs64;
#else
using StatFs = statfs;
#endif

namespace LIBC_NAMESPACE_DECL {
static int fstatfs(int fd, StatFs *buf) {
using namespace statfs_utils;
if (cpp::optional<StatFs> result = linux_fstatfs(fd)) {
*buf = *result;
return 0;
}
return -1;
}
} // namespace LIBC_NAMESPACE_DECL

struct PathFD {
int fd;
explicit PathFD(const char *path)
: fd(LIBC_NAMESPACE::open(path, O_CLOEXEC | O_PATH)) {}
~PathFD() { LIBC_NAMESPACE::close(fd); }
operator int() const { return fd; }
};

TEST(LlvmLibcSysStatvfsTest, FstatfsBasic) {
StatFs buf;
ASSERT_THAT(LIBC_NAMESPACE::fstatfs(PathFD("/"), &buf), Succeeds());
ASSERT_THAT(LIBC_NAMESPACE::fstatfs(PathFD("/proc"), &buf), Succeeds());
ASSERT_EQ(buf.f_type, static_cast<decltype(buf.f_type)>(PROC_SUPER_MAGIC));
ASSERT_THAT(LIBC_NAMESPACE::fstatfs(PathFD("/sys"), &buf), Succeeds());
ASSERT_EQ(buf.f_type, static_cast<decltype(buf.f_type)>(SYSFS_MAGIC));
TEST(LlvmLibcSysFStatvfsTest, FStatvfsBasic) {
struct statvfs buf;

int fd = LIBC_NAMESPACE::open("/", O_PATH);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);

// The root of the file directory must always exist
ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Succeeds());
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
}

TEST(LlvmLibcSysStatvfsTest, FstatvfsInvalidFD) {
TEST(LlvmLibcSysFStatvfsTest, FStatvfsInvalidPath) {
struct statvfs buf;
ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(-1, &buf), Fails(EBADF));

constexpr const char *FILENAME = "testdata/statvfs.testdir";
auto TEST_DIR = libc_make_test_file_path(FILENAME);

ASSERT_THAT(LIBC_NAMESPACE::mkdirat(AT_FDCWD, TEST_DIR, S_IRWXU),
Succeeds(0));

int fd = LIBC_NAMESPACE::open(TEST_DIR, O_PATH);
ASSERT_ERRNO_SUCCESS();
ASSERT_GT(fd, 0);

// create the file, assert it exists, then delete it and assert it doesn't
// exist anymore.

ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Succeeds());

ASSERT_THAT(LIBC_NAMESPACE::rmdir(TEST_DIR), Succeeds(0));

ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Fails(ENOENT));
ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));
ASSERT_THAT(LIBC_NAMESPACE::fstatvfs(fd, &buf), Fails(ENOENT));
}
Loading