Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "RedundantMemberInitCheck.h"
#include "../utils/LexerUtils.h"
#include "../utils/Matchers.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
Expand All @@ -18,52 +19,80 @@ using namespace clang::tidy::matchers;

namespace clang::tidy::readability {

static SourceRange
getFullInitRangeInclWhitespaces(SourceRange Range, const SourceManager &SM,
const LangOptions &LangOpts) {
const Token PrevToken =
utils::lexer::getPreviousToken(Range.getBegin(), SM, LangOpts, false);
if (PrevToken.is(tok::unknown))
return Range;

if (PrevToken.isNot(tok::equal))
return {PrevToken.getEndLoc(), Range.getEnd()};

return getFullInitRangeInclWhitespaces(
{PrevToken.getLocation(), Range.getEnd()}, SM, LangOpts);
}

void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreBaseInCopyConstructors",
IgnoreBaseInCopyConstructors);
}

void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
auto ConstructorMatcher =
cxxConstructExpr(argumentCountIs(0),
hasDeclaration(cxxConstructorDecl(ofClass(cxxRecordDecl(
unless(isTriviallyDefaultConstructible()))))))
.bind("construct");

Finder->addMatcher(
cxxConstructorDecl(
unless(isDelegatingConstructor()), ofClass(unless(isUnion())),
forEachConstructorInitializer(
cxxCtorInitializer(
withInitializer(
cxxConstructExpr(
hasDeclaration(
cxxConstructorDecl(ofClass(cxxRecordDecl(
unless(isTriviallyDefaultConstructible()))))))
.bind("construct")),
unless(forField(hasType(isConstQualified()))),
unless(forField(hasParent(recordDecl(isUnion())))))
cxxCtorInitializer(withInitializer(ConstructorMatcher),
unless(forField(fieldDecl(
anyOf(hasType(isConstQualified()),
hasParent(recordDecl(isUnion())))))))
.bind("init")))
.bind("constructor"),
this);

Finder->addMatcher(fieldDecl(hasInClassInitializer(ConstructorMatcher),
unless(hasParent(recordDecl(isUnion()))))
.bind("field"),
this);
}

void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");

if (const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field")) {
const Expr *Init = Field->getInClassInitializer();
diag(Construct->getExprLoc(), "initializer for member %0 is redundant")
<< Field
<< FixItHint::CreateRemoval(getFullInitRangeInclWhitespaces(
Init->getSourceRange(), *Result.SourceManager, getLangOpts()));
return;
}

const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
const auto *ConstructorDecl =
Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");

if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
Init->isBaseInitializer())
return;

if (Construct->getNumArgs() == 0 ||
Construct->getArg(0)->isDefaultArgument()) {
if (Init->isAnyMemberInitializer()) {
diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
<< Init->getAnyMember()
<< FixItHint::CreateRemoval(Init->getSourceRange());
} else {
diag(Init->getSourceLocation(),
"initializer for base class %0 is redundant")
<< Construct->getType()
<< FixItHint::CreateRemoval(Init->getSourceRange());
}
if (Init->isAnyMemberInitializer()) {
diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
<< Init->getAnyMember()
<< FixItHint::CreateRemoval(Init->getSourceRange());
} else {
diag(Init->getSourceLocation(),
"initializer for base class %0 is redundant")
<< Construct->getType()
<< FixItHint::CreateRemoval(Init->getSourceRange());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,13 @@ class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
}

bool dataTraverseStmtPre(Stmt *S) {
if (S && !shouldIgnore(S))
if (!S) {
return true;
}
if (Check->IgnoreMacros && S->getBeginLoc().isMacroID()) {
return false;
}
if (!shouldIgnore(S))
StmtStack.push_back(S);
return true;
}
Expand Down Expand Up @@ -583,6 +589,7 @@ class SimplifyBooleanExprCheck::Visitor : public RecursiveASTVisitor<Visitor> {
SimplifyBooleanExprCheck::SimplifyBooleanExprCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IgnoreMacros(Options.get("IgnoreMacros", false)),
ChainedConditionalReturn(Options.get("ChainedConditionalReturn", false)),
ChainedConditionalAssignment(
Options.get("ChainedConditionalAssignment", false)),
Expand Down Expand Up @@ -671,6 +678,7 @@ void SimplifyBooleanExprCheck::reportBinOp(const ASTContext &Context,
}

void SimplifyBooleanExprCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreMacros", IgnoreMacros);
Options.store(Opts, "ChainedConditionalReturn", ChainedConditionalReturn);
Options.store(Opts, "ChainedConditionalAssignment",
ChainedConditionalAssignment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class SimplifyBooleanExprCheck : public ClangTidyCheck {
StringRef Description, SourceRange ReplacementRange,
StringRef Replacement);

const bool IgnoreMacros;
const bool ChainedConditionalReturn;
const bool ChainedConditionalAssignment;
const bool SimplifyDeMorgan;
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/utils/HeaderGuard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ void HeaderGuardCheck::registerPPCallbacks(const SourceManager &SM,

std::string HeaderGuardCheck::sanitizeHeaderGuard(StringRef Guard) {
// Only reserved identifiers are allowed to start with an '_'.
return Guard.drop_while([](char C) { return C == '_'; }).str();
return Guard.ltrim('_').str();
}

bool HeaderGuardCheck::shouldSuggestEndifComment(StringRef FileName) {
Expand Down
56 changes: 41 additions & 15 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -224,18 +224,23 @@ New checks
Recommends the smallest possible underlying type for an ``enum`` or ``enum``
class based on the range of its enumerators.

- New :doc:`readability-reference-to-constructed-temporary
<clang-tidy/checks/readability/reference-to-constructed-temporary>` check.
- New :doc:`readability-avoid-nested-conditional-operator
<clang-tidy/checks/readability/avoid-nested-conditional-operator>` check.

Detects C++ code where a reference variable is used to extend the lifetime
of a temporary object that has just been constructed.
Identifies instances of nested conditional operators in the code.

- New :doc:`readability-avoid-return-with-void-value
<clang-tidy/checks/readability/avoid-return-with-void-value>` check.

Finds return statements with ``void`` values used within functions with
``void`` result types.

- New :doc:`readability-reference-to-constructed-temporary
<clang-tidy/checks/readability/reference-to-constructed-temporary>` check.

Detects C++ code where a reference variable is used to extend the lifetime
of a temporary object that has just been constructed.

New check aliases
^^^^^^^^^^^^^^^^^

Expand All @@ -260,6 +265,14 @@ Changes in existing checks
casting during type conversions at variable initialization, now with improved
compatibility for C++17 and later versions.

- Improved :doc:`bugprone-exception-escape
<clang-tidy/checks/bugprone/exception-escape>` check by extending the default
check function names to include ``iter_swap`` and ``iter_move``.

- Improved :doc:`bugprone-implicit-widening-of-multiplication-result
<clang-tidy/checks/bugprone/implicit-widening-of-multiplication-result>` check
to correctly emit fixes.

- Improved :doc:`bugprone-lambda-function-name
<clang-tidy/checks/bugprone/lambda-function-name>` check by adding option
`IgnoreMacros` to ignore warnings in macros.
Expand Down Expand Up @@ -387,7 +400,7 @@ Changes in existing checks

- Improved :doc:`misc-unused-using-decls
<clang-tidy/checks/misc/unused-using-decls>` check to avoid false positive when
using in elaborated type and only check cpp files.
using in elaborated type and only check C++ files.

- Improved :doc:`modernize-avoid-bind
<clang-tidy/checks/modernize/avoid-bind>` check to
Expand Down Expand Up @@ -427,38 +440,41 @@ Changes in existing checks

- Improved :doc:`modernize-use-using
<clang-tidy/checks/modernize/use-using>` check to fix function pointer and
forward declared ``typedef`` correctly. Added option `IgnoreExternC` to ignore ``typedef``
declaration in ``extern "C"`` scope.
forward declared ``typedef`` correctly. Added option `IgnoreExternC` to ignore
``typedef`` declaration in ``extern "C"`` scope.

- Improved :doc:`performance-faster-string-find
<clang-tidy/checks/performance/faster-string-find>` check to properly escape
single quotes.

- Improved :doc:`performance-noexcept-move-constructor
<clang-tidy/checks/performance/noexcept-move-constructor>` to better handle
conditional noexcept expressions, eliminating false-positives.
conditional ``noexcept`` expressions, eliminating false-positives.

- Improved :doc:`performance-noexcept-swap
<clang-tidy/checks/performance/noexcept-swap>` check to enforce a stricter
match with the swap function signature and better handling of condition
noexcept expressions, eliminating false-positives.
``noexcept`` expressions, eliminating false-positives. ``iter_swap`` function
name is checked by default.

- Improved :doc:`readability-braces-around-statements
<clang-tidy/checks/readability/braces-around-statements>` check to
ignore false-positive for ``if constexpr`` in lambda expression.

- Improved :doc:`readability-avoid-const-params-in-decls
<clang-tidy/checks/readability/avoid-const-params-in-decls>` diagnositics to
highlight the const location
<clang-tidy/checks/readability/avoid-const-params-in-decls>` diagnostics to
highlight the ``const`` location

- Improved :doc:`readability-container-contains
<clang-tidy/checks/readability/container-contains>` to correctly handle
interger literals with suffixes in fix-its.
integer literals with suffixes in fix-its.

- Improved :doc:`readability-container-size-empty
<clang-tidy/checks/readability/container-size-empty>` check to
detect comparison between string and empty string literals and support
``length()`` method as an alternative to ``size()``.
``length()`` method as an alternative to ``size()``. Resolved false positives
tied to negative values from size-like methods, and one triggered by size
checks below zero.

- Improved :doc:`readability-function-size
<clang-tidy/checks/readability/function-size>` check configuration to use
Expand All @@ -476,13 +492,14 @@ Changes in existing checks
``camel_Snake_Case`` now detect more invalid identifier names. Fields in
anonymous records (i.e. anonymous structs and unions) now can be checked with
the naming rules associated with their enclosing scopes rather than the naming
rules of public struct/union members.
rules of public ``struct``/``union`` members.

- Improved :doc:`readability-implicit-bool-conversion
<clang-tidy/checks/readability/implicit-bool-conversion>` check to take
do-while loops into account for the `AllowIntegerConditions` and
`AllowPointerConditions` options. It also now provides more consistent
suggestions when parentheses are added to the return value.
suggestions when parentheses are added to the return value. It also ignores
false-positives for comparison containing bool bitfield.

- Improved :doc:`readability-misleading-indentation
<clang-tidy/checks/readability/misleading-indentation>` check to ignore
Expand All @@ -492,6 +509,15 @@ Changes in existing checks
<clang-tidy/checks/readability/non-const-parameter>` check to ignore
false-positives in initializer list of record.

- Improved :doc:`readability-redundant-member-init
<clang-tidy/checks/readability/redundant-member-init>` check to now also
detect redundant in-class initializers.

- Improved :doc:`readability-simplify-boolean-expr
<clang-tidy/checks/readability/simplify-boolean-expr>` check by adding the
new option `IgnoreMacros` that allows to ignore boolean expressions originating
from expanded macros.

- Improved :doc:`readability-simplify-subscript-expr
<clang-tidy/checks/readability/simplify-subscript-expr>` check by extending
the default value of the `Types` option to include ``std::span``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ should not. The functions which should not throw exceptions are the following:
* Move assignment operators
* The ``main()`` functions
* ``swap()`` functions
* ``iter_swap()`` functions
* ``iter_move()`` functions
* Functions marked with ``throw()`` or ``noexcept``
* Other functions given as option

Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ Clang-Tidy Checks
:doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
:doc:`portability-std-allocator-const <portability/std-allocator-const>`,
:doc:`readability-avoid-const-params-in-decls <readability/avoid-const-params-in-decls>`, "Yes"
:doc:`readability-avoid-nested-conditional-operator <readability/avoid-nested-conditional-operator>`,
:doc:`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>`,
:doc:`readability-avoid-unconditional-preprocessor-if <readability/avoid-unconditional-preprocessor-if>`,
:doc:`readability-braces-around-statements <readability/braces-around-statements>`, "Yes"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
performance-noexcept-swap
=========================

The check flags user-defined swap functions not marked with ``noexcept`` or
The check flags user-defined swap and iter_swap functions not marked with ``noexcept`` or
marked with ``noexcept(expr)`` where ``expr`` evaluates to ``false``
(but is not a ``false`` literal itself).

When a swap function is marked as ``noexcept``, it assures the compiler that
When a swap or iter_swap function is marked as ``noexcept``, it assures the compiler that
no exceptions will be thrown during the swapping of two objects, which allows
the compiler to perform certain optimizations such as omitting exception
handling code.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.. title:: clang-tidy - readability-avoid-nested-conditional-operator

readability-avoid-nested-conditional-operator
=============================================

Identifies instances of nested conditional operators in the code.

Nested conditional operators, also known as ternary operators, can contribute
to reduced code readability and comprehension. So they should be split as
several statements and stored the intermediate results in temporary variable.

Examples:

.. code-block:: c++

int NestInConditional = (condition1 ? true1 : false1) ? true2 : false2;
int NestInTrue = condition1 ? (condition2 ? true1 : false1) : false2;
int NestInFalse = condition1 ? true1 : condition2 ? true2 : false1;

This check implements part of `AUTOSAR C++14 Rule A5-16-1
<https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf>`_.
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ Example

.. code-block:: c++

// Explicitly initializing the member s is unnecessary.
// Explicitly initializing the member s and v is unnecessary.
class Foo {
public:
Foo() : s() {}

private:
std::string s;
std::vector<int> v {};
};

Options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ Examples:
Options
-------

.. option:: IgnoreMacros

If `true`, ignore boolean expressions originating from expanded macros.
Default is `false`.

.. option:: ChainedConditionalReturn

If `true`, conditional boolean return statements at the end of an
Expand All @@ -99,8 +104,8 @@ Options

.. option:: SimplifyDeMorganRelaxed

If `true`, :option:`SimplifyDeMorgan` will also transform negated
conjunctions and disjunctions where there is no negation on either operand.
If `true`, :option:`SimplifyDeMorgan` will also transform negated
conjunctions and disjunctions where there is no negation on either operand.
This option has no effect if :option:`SimplifyDeMorgan` is `false`.
Default is `false`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,16 @@ void swap(int&, int&) {
throw 1;
}

void iter_swap(int&, int&) {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'iter_swap' which should not throw exceptions
throw 1;
}

void iter_move(int&) {
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'iter_move' which should not throw exceptions
throw 1;
}

namespace std {
class bad_alloc {};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ char *t0(char *base, int a, int b) {
// CHECK-NOTES-CXX: static_cast<ptrdiff_t>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:16: note: perform multiplication in a wider type
// CHECK-NOTES-C: (ptrdiff_t)
// CHECK-NOTES-CXX: static_cast<ptrdiff_t>()
// CHECK-NOTES-CXX: static_cast<ptrdiff_t>( )
}
void *t1(char *base, int a, int b) {
return &((a * b)[base]);
Expand All @@ -35,7 +35,7 @@ char *t2(char *base, unsigned int a, int b) {
// CHECK-NOTES-CXX: static_cast<size_t>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:16: note: perform multiplication in a wider type
// CHECK-NOTES-C: (size_t)
// CHECK-NOTES-CXX: static_cast<size_t>()
// CHECK-NOTES-CXX: static_cast<size_t>( )
}

char *t3(char *base, int a, unsigned int b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ long t0(int a, int b) {
// CHECK-NOTES-CXX: static_cast<long>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:10: note: perform multiplication in a wider type
// CHECK-NOTES-C: (long)
// CHECK-NOTES-CXX: static_cast<long>()
// CHECK-NOTES-CXX: static_cast<long>( )
}
unsigned long t1(int a, int b) {
return a * b;
Expand All @@ -28,7 +28,7 @@ unsigned long t1(int a, int b) {
// CHECK-NOTES-CXX: static_cast<unsigned long>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:10: note: perform multiplication in a wider type
// CHECK-NOTES-C: (long)
// CHECK-NOTES-CXX: static_cast<long>()
// CHECK-NOTES-CXX: static_cast<long>( )
}

long t2(unsigned int a, int b) {
Expand All @@ -39,7 +39,7 @@ long t2(unsigned int a, int b) {
// CHECK-NOTES-CXX: static_cast<long>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:10: note: perform multiplication in a wider type
// CHECK-NOTES-C: (unsigned long)
// CHECK-NOTES-CXX: static_cast<unsigned long>()
// CHECK-NOTES-CXX: static_cast<unsigned long>( )
}
unsigned long t3(unsigned int a, int b) {
return a * b;
Expand All @@ -49,7 +49,7 @@ unsigned long t3(unsigned int a, int b) {
// CHECK-NOTES-CXX: static_cast<unsigned long>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:10: note: perform multiplication in a wider type
// CHECK-NOTES-C: (unsigned long)
// CHECK-NOTES-CXX: static_cast<unsigned long>()
// CHECK-NOTES-CXX: static_cast<unsigned long>( )
}

long t4(int a, unsigned int b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ char *t0(char *base, int a, int b) {
// CHECK-NOTES-CXX: static_cast<ptrdiff_t>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:17: note: perform multiplication in a wider type
// CHECK-NOTES-C: (ptrdiff_t)
// CHECK-NOTES-CXX: static_cast<ptrdiff_t>()
// CHECK-NOTES-CXX: static_cast<ptrdiff_t>( )
}
char *t1(char *base, int a, int b) {
return a * b + base;
Expand All @@ -35,7 +35,7 @@ char *t2(char *base, unsigned int a, int b) {
// CHECK-NOTES-CXX: static_cast<size_t>( )
// CHECK-NOTES-ALL: :[[@LINE-5]]:17: note: perform multiplication in a wider type
// CHECK-NOTES-C: (size_t)
// CHECK-NOTES-CXX: static_cast<size_t>()
// CHECK-NOTES-CXX: static_cast<size_t>( )
}

char *t3(char *base, int a, unsigned int b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ void swap(A &, A &);
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap functions should be marked noexcept [performance-noexcept-swap]
// CHECK-FIXES: void swap(A &, A &) noexcept ;

void iter_swap(A &, A &);
// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: swap functions should be marked noexcept [performance-noexcept-swap]
// CHECK-FIXES: void iter_swap(A &, A &) noexcept ;

struct B {
static constexpr bool kFalse = false;
void swap(B &) noexcept(kFalse);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %check_clang_tidy %s readability-avoid-nested-conditional-operator %t

int NestInConditional = (true ? true : false) ? 1 : 2;
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: conditional operator is used as sub-expression of parent conditional operator, refrain from using nested conditional operators
// CHECK-MESSAGES: :[[@LINE-2]]:25: note: parent conditional operator here

int NestInTrue = true ? (true ? 1 : 2) : 2;
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: conditional operator is used as sub-expression of parent conditional operator, refrain from using nested conditional operators
// CHECK-MESSAGES: :[[@LINE-2]]:18: note: parent conditional operator here

int NestInFalse = true ? 1 : true ? 1 : 2;
// CHECK-MESSAGES: :[[@LINE-1]]:30: warning: conditional operator is used as sub-expression of parent conditional operator, refrain from using nested conditional operators
// CHECK-MESSAGES: :[[@LINE-2]]:19: note: parent conditional operator here
int NestInFalse2 = true ? 1 : (true ? 1 : 2);
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: conditional operator is used as sub-expression of parent conditional operator, refrain from using nested conditional operators
// CHECK-MESSAGES: :[[@LINE-2]]:20: note: parent conditional operator here

int NestWithParensis = true ? 1 : ((((true ? 1 : 2))));
// CHECK-MESSAGES: :[[@LINE-1]]:39: warning: conditional operator is used as sub-expression of parent conditional operator, refrain from using nested conditional operators
// CHECK-MESSAGES: :[[@LINE-2]]:24: note: parent conditional operator here

#define CONDITIONAL_EXPR (true ? 1 : 2)
// not diag for macro since it will not reduce readability
int NestWithMacro = true ? CONDITIONAL_EXPR : 2;
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class TemplatedContainer {
public:
bool operator==(const TemplatedContainer<T>& other) const;
bool operator!=(const TemplatedContainer<T>& other) const;
int size() const;
unsigned long size() const;
bool empty() const;
};

Expand All @@ -42,7 +42,7 @@ class PrivateEmpty {
public:
bool operator==(const PrivateEmpty<T>& other) const;
bool operator!=(const PrivateEmpty<T>& other) const;
int size() const;
unsigned long size() const;
private:
bool empty() const;
};
Expand All @@ -61,7 +61,7 @@ struct EnumSize {
class Container {
public:
bool operator==(const Container& other) const;
int size() const;
unsigned long size() const;
bool empty() const;
};

Expand All @@ -70,13 +70,13 @@ class Derived : public Container {

class Container2 {
public:
int size() const;
unsigned long size() const;
bool empty() const { return size() == 0; }
};

class Container3 {
public:
int size() const;
unsigned long size() const;
bool empty() const;
};

Expand All @@ -85,7 +85,7 @@ bool Container3::empty() const { return this->size() == 0; }
class Container4 {
public:
bool operator==(const Container4& rhs) const;
int size() const;
unsigned long size() const;
bool empty() const { return *this == Container4(); }
};

Expand Down Expand Up @@ -815,3 +815,49 @@ bool testNotEmptyStringLiterals(const std::string& s)
using namespace std::string_literals;
return s == "foo"s;
}

namespace PR72619 {
struct SS {
bool empty() const;
int size() const;
};

struct SU {
bool empty() const;
unsigned size() const;
};

void f(const SU& s) {
if (s.size() < 0) {}
if (0 > s.size()) {}
if (s.size() >= 0) {}
if (0 <= s.size()) {}
if (s.size() < 1)
;
// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
if (1 > s.size())
;
// CHECK-MESSAGES: :[[@LINE-2]]:13: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
if (s.size() <= 0)
;
// CHECK-MESSAGES: :[[@LINE-2]]:9: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
if (0 >= s.size())
;
// CHECK-MESSAGES: :[[@LINE-2]]:14: warning: the 'empty' method should be used to check for emptiness instead of 'size' [readability-container-size-empty]
// CHECK-FIXES: {{^ }}if (s.empty()){{$}}
}

void f(const SS& s) {
if (s.size() < 0) {}
if (0 > s.size()) {}
if (s.size() >= 0) {}
if (0 <= s.size()) {}
if (s.size() < 1) {}
if (1 > s.size()) {}
if (s.size() <= 0) {}
if (0 >= s.size()) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ int* functionReturningPointer();
struct Struct {
int member;
unsigned bitfield : 1;
bool boolfield : 1;
};


Expand All @@ -28,6 +29,8 @@ void implicitConversionIntegerToBoolInConditionalsIsAllowed() {
if (!s.member) {}
if (s.bitfield) {}
if (!s.bitfield) {}
if (s.boolfield == true) {}
if (s.boolfield != true) {}
if (functionReturningInt()) {}
if (!functionReturningInt()) {}
if (functionReturningInt() && functionReturningPointer()) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,55 @@ struct NF15 {
S s2;
};
};

// Direct in-class initialization with default constructor
struct D1 {
S f1 {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f1' is redundant
// CHECK-FIXES: S f1;
};

// Direct in-class initialization with constructor with default argument
struct D2 {
T f2 {};
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: initializer for member 'f2' is redundant
// CHECK-FIXES: T f2;
};

// Direct in-class initialization with default constructor (assign)
struct D3 {
S f3 = {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f3' is redundant
// CHECK-FIXES: S f3;
};

// Direct in-class initialization with constructor with default argument (assign)
struct D4 {
T f4 = {};
// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: initializer for member 'f4' is redundant
// CHECK-FIXES: T f4;
};

// Templated class independent type
template <class V>
struct D5 {
S f5 /*comment*/ = S();
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: initializer for member 'f5' is redundant
// CHECK-FIXES: S f5 /*comment*/;
};
D5<int> d5i;
D5<S> d5s;

struct D6 {
UsesCleanup uc2{};
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: initializer for member 'uc2' is redundant
// CHECK-FIXES: UsesCleanup uc2;
};

template<typename V>
struct D7 {
V f7;
};

D7<int> d7i;
D7<S> d7s;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %check_clang_tidy -check-suffixes=,MACROS %s readability-simplify-boolean-expr %t

// Ignore expressions in macros.
// RUN: %check_clang_tidy %s readability-simplify-boolean-expr %t \
// RUN: -- -config="{CheckOptions: {readability-simplify-boolean-expr.IgnoreMacros: true}}" \
// RUN: --

#define NEGATE(expr) !(expr)

bool without_macro(bool a, bool b) {
return !(!a && b);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: return a || !b;
}

bool macro(bool a, bool b) {
return NEGATE(!a && b);
// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:12: warning: boolean expression can be simplified by DeMorgan's theorem
// CHECK-FIXES: return NEGATE(!a && b);
}
5 changes: 5 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4432,6 +4432,11 @@ the configuration (without a prefix: ``Auto``).
**PenaltyBreakOpenParenthesis** (``Unsigned``) :versionbadge:`clang-format 14` :ref:`¶ <PenaltyBreakOpenParenthesis>`
The penalty for breaking after ``(``.

.. _PenaltyBreakScopeResolution:

**PenaltyBreakScopeResolution** (``Unsigned``) :versionbadge:`clang-format 18` :ref:`¶ <PenaltyBreakScopeResolution>`
The penalty for breaking after ``::``.

.. _PenaltyBreakString:

**PenaltyBreakString** (``Unsigned``) :versionbadge:`clang-format 3.7` :ref:`¶ <PenaltyBreakString>`
Expand Down
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,8 @@ Miscellaneous Clang Crashes Fixed
- Fixed a crash when a lambda marked as ``static`` referenced a captured
variable in an expression.
`Issue 74608 <https://github.com/llvm/llvm-project/issues/74608>`_
- Fixed a crash with modules and a ``constexpr`` destructor.
`Issue 68702 <https://github.com/llvm/llvm-project/issues/68702>`_


OpenACC Specific Changes
Expand Down Expand Up @@ -1131,6 +1133,7 @@ clang-format
- Add ``BreakAdjacentStringLiterals`` option.
- Add ``ObjCPropertyAttributeOrder`` which can be used to sort ObjC property
attributes (like ``nonatomic, strong, nullable``).
- Add ``PenaltyBreakScopeResolution`` option.
- Add ``.clang-format-ignore`` files.
- Add ``AlignFunctionPointers`` sub-option for ``AlignConsecutiveDeclarations``.

Expand Down
54 changes: 54 additions & 0 deletions clang/docs/UsersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3963,6 +3963,60 @@ implicitly included in later levels.
- ``-march=x86-64-v3``: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
- ``-march=x86-64-v4``: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL

`Intel AVX10 ISA <https://cdrdv2.intel.com/v1/dl/getContent/784267>`_ is
a major new vector ISA incorporating the modern vectorization aspects of
Intel AVX-512. This ISA will be supported on all future Intel processors.
Users are supposed to use the new options ``-mavx10.N`` and ``-mavx10.N-512``
on these processors and should not use traditional AVX512 options anymore.

The ``N`` in ``-mavx10.N`` represents a continuous integer number starting
from ``1``. ``-mavx10.N`` is an alias of ``-mavx10.N-256``, which means to
enable all instructions within AVX10 version N at a maximum vector length of
256 bits. ``-mavx10.N-512`` enables all instructions at a maximum vector
length of 512 bits, which is a superset of instructions ``-mavx10.N`` enabled.

Current binaries built with AVX512 features can run on Intel AVX10/512 capable
processors without re-compile, but cannot run on AVX10/256 capable processors.
Users need to re-compile their code with ``-mavx10.N``, and maybe update some
code that calling to 512-bit X86 specific intrinsics and passing or returning
512-bit vector types in function call, if they want to run on AVX10/256 capable
processors. Binaries built with ``-mavx10.N`` can run on both AVX10/256 and
AVX10/512 capable processors.

Users can add a ``-mno-evex512`` in the command line with AVX512 options if
they want to run the binary on both legacy AVX512 and new AVX10/256 capable
processors. The option has the same constraints as ``-mavx10.N``, i.e.,
cannot call to 512-bit X86 specific intrinsics and pass or return 512-bit vector
types in function call.

Users should avoid using AVX512 features in function target attributes when
developing code for AVX10. If they have to do so, they need to add an explicit
``evex512`` or ``no-evex512`` together with AVX512 features for 512-bit or
non-512-bit functions respectively to avoid unexpected code generation. Both
command line option and target attribute of EVEX512 feature can only be used
with AVX512. They don't affect vector size of AVX10.

User should not mix the use AVX10 and AVX512 options together at any time,
because the option combinations are conflicting sometimes. For example, a
combination of ``-mavx512f -mavx10.1-256`` doesn't show a clear intention to
compiler, since instructions in AVX512F and AVX10.1/256 intersect but do not
overlap. In this case, compiler will emit warning for it, but the behavior
is determined. It will generate the same code as option ``-mavx10.1-512``.
A similar case is ``-mavx512f -mavx10.2-256``, which equals to
``-mavx10.1-512 -mavx10.2-256``, because ``avx10.2-256`` implies ``avx10.1-256``
and ``-mavx512f -mavx10.1-256`` equals to ``-mavx10.1-512``.

There are some new macros introduced with AVX10 support. ``-mavx10.1-256`` will
enable ``__AVX10_1__`` and ``__EVEX256__``, while ``-mavx10.1-512`` enables
``__AVX10_1__``, ``__EVEX256__``, ``__EVEX512__`` and ``__AVX10_1_512__``.
Besides, both ``-mavx10.1-256`` and ``-mavx10.1-512`` will enable all AVX512
feature specific macros. A AVX512 feature will enable both ``__EVEX256__``,
``__EVEX512__`` and its own macro. So ``__EVEX512__`` can be used to guard code
that can run on both legacy AVX512 and AVX10/512 capable processors but cannot
run on AVX10/256, while a AVX512 macro like ``__AVX512F__`` cannot tell the
difference among the three options. Users need to check additional macros
``__AVX10_1__`` and ``__EVEX512__`` if they want to make distinction.

ARM
^^^

Expand Down
23 changes: 19 additions & 4 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -4036,12 +4036,27 @@ class FunctionType : public Type {
SME_NormalFunction = 0,
SME_PStateSMEnabledMask = 1 << 0,
SME_PStateSMCompatibleMask = 1 << 1,
SME_PStateZASharedMask = 1 << 2,
SME_PStateZAPreservedMask = 1 << 3,
SME_AttributeMask = 0b111'111 // We only support maximum 6 bits because of the
// bitmask in FunctionTypeExtraBitfields.

// Describes the value of the state using ArmStateValue.
SME_ZAShift = 2,
SME_ZAMask = 0b111 << SME_ZAShift,

SME_AttributeMask = 0b111'111 // We only support maximum 6 bits because of
// the bitmask in FunctionTypeExtraBitfields.
};

enum ArmStateValue : unsigned {
ARM_None = 0,
ARM_Preserves = 1,
ARM_In = 2,
ARM_Out = 3,
ARM_InOut = 4,
};

static ArmStateValue getArmZAState(unsigned AttrBits) {
return (ArmStateValue)((AttrBits & SME_ZAMask) >> SME_ZAShift);
}

/// A simple holder for various uncommon bits which do not fit in
/// FunctionTypeBitfields. Aligned to alignof(void *) to maintain the
/// alignment of subsequent objects in TrailingObjects.
Expand Down
49 changes: 35 additions & 14 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2539,16 +2539,45 @@ def ArmStreamingCompatible : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Documentation = [ArmSmeStreamingCompatibleDocs];
}

def ArmSharedZA : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_shared_za">];
def ArmNew : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_new">];
let Args = [VariadicStringArgument<"NewArgs">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [ArmNewDocs];

let AdditionalMembers = [{
bool isNewZA() const {
return llvm::is_contained(newArgs(), "za");
}
}];
}

def ArmIn : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_in">];
let Args = [VariadicStringArgument<"InArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmInDocs];
}

def ArmOut : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_out">];
let Args = [VariadicStringArgument<"OutArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmOutDocs];
}

def ArmInOut : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_inout">];
let Args = [VariadicStringArgument<"InOutArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmSmeSharedZADocs];
let Documentation = [ArmInOutDocs];
}

def ArmPreservesZA : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_preserves_za">];
def ArmPreserves : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_preserves">];
let Args = [VariadicStringArgument<"PreserveArgs">];
let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>;
let Documentation = [ArmSmePreservesZADocs];
let Documentation = [ArmPreservesDocs];
}

def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
Expand All @@ -2557,14 +2586,6 @@ def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
let Documentation = [ArmSmeLocallyStreamingDocs];
}

def ArmNewZA : InheritableAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_new_za">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [ArmSmeNewZADocs];
}
def : MutualExclusions<[ArmNewZA, ArmSharedZA]>;
def : MutualExclusions<[ArmNewZA, ArmPreservesZA]>;


def Pure : InheritableAttr {
let Spellings = [GCC<"pure">];
Expand Down
82 changes: 65 additions & 17 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -6861,30 +6861,73 @@ without changing modes.
}];
}

def ArmSmeSharedZADocs : Documentation {
def ArmInDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_shared_za`` keyword applies to prototyped function types and specifies
that the function shares SME's matrix storage (ZA) with its caller. This
means that:
The ``__arm_in`` keyword applies to prototyped function types and specifies
that the function shares a given state S with its caller. For ``__arm_in``, the
function takes the state S as input and returns with the state S unchanged.

* the function requires that the processor implements the Scalable Matrix
Extension (SME).
The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* the function enters with ZA in an active state.
* ``"za"`` for Matrix Storage (requires SME)

* the function returns with ZA in an active state.
The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmSmePreservesZADocs : Documentation {
def ArmOutDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_preserves_za`` keyword applies to prototyped function types and
specifies that the function does not modify ZA state.
The ``__arm_out`` keyword applies to prototyped function types and specifies
that the function shares a given state S with its caller. For ``__arm_out``,
the function ignores the incoming state for S and returns new state for S.

The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmInOutDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_inout`` keyword applies to prototyped function types and specifies
that the function shares a given state S with its caller. For ``__arm_inout``,
the function takes the state S as input and returns new state for S.

The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmPreservesDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_preserves`` keyword applies to prototyped function types and
specifies that the function does not read a given state S and returns
with state S unchanged.

The attribute takes string arguments to instruct the compiler which state
is shared. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

The attributes ``__arm_in(S)``, ``__arm_out(S)``, ``__arm_inout(S)`` and
``__arm_preserves(S)`` are all mutually exclusive for the same state S.
}];
}

def ArmSmeLocallyStreamingDocs : Documentation {
let Category = DocCatArmSmeAttributes;
Expand All @@ -6907,13 +6950,18 @@ at the end of the function.
}];
}

def ArmSmeNewZADocs : Documentation {
def ArmNewDocs : Documentation {
let Category = DocCatArmSmeAttributes;
let Content = [{
The ``__arm_new_za`` keyword applies to function declarations and specifies
that the function will be set up with a fresh ZA context.
The ``__arm_new`` keyword applies to function declarations and specifies
that the function will create a new scope for state S.

The attribute takes string arguments to instruct the compiler for which state
to create new scope. The supported states for S are:

* ``"za"`` for Matrix Storage (requires SME)

This means that:
For state ``"za"``, this means that:

* the function requires that the target processor implements the Scalable Matrix
Extension (SME).
Expand All @@ -6924,8 +6972,8 @@ This means that:

* the function will disable PSTATE.ZA (by setting it to 0) before returning.

For ``__arm_new_za`` functions Clang will set up the ZA context automatically
on entry to the function, and disable it before returning. For example, if ZA is
For ``__arm_new("za")`` functions Clang will set up the ZA context automatically
on entry to the function and disable it before returning. For example, if ZA is
in a dormant state Clang will generate the code to commit a lazy-save and set up
a new ZA state before executing user code.
}];
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Basic/AttributeCommonInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,19 @@ class AttributeCommonInfo {
return SpellingIndex != SpellingNotCalculated;
}
};

inline bool doesKeywordAttributeTakeArgs(tok::TokenKind Kind) {
switch (Kind) {
default:
return false;
#define KEYWORD_ATTRIBUTE(NAME, HASARG) \
case tok::kw_##NAME: \
return HASARG;
#include "clang/Basic/RegularKeywordAttrInfo.inc"
#undef KEYWORD_ATTRIBUTE
}
}

} // namespace clang

#endif // LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/BuiltinsPPC.def
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ BUILTIN(__builtin_ppc_fctiw, "dd", "")
BUILTIN(__builtin_ppc_fctiwz, "dd", "")
BUILTIN(__builtin_ppc_fctudz, "dd", "")
BUILTIN(__builtin_ppc_fctuwz, "dd", "")

// fence builtin prevents all instructions moved across it
BUILTIN(__builtin_ppc_fence, "v", "")

BUILTIN(__builtin_ppc_swdiv_nochk, "ddd", "")
BUILTIN(__builtin_ppc_swdivs_nochk, "fff", "")
BUILTIN(__builtin_ppc_alignx, "vIivC*", "nc")
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
SOURCE Attr.td
TARGET ClangAttrSubjectMatchRuleList)

clang_tablegen(AttrTokenKinds.inc -gen-clang-attr-token-kinds
clang_tablegen(RegularKeywordAttrInfo.inc -gen-clang-regular-keyword-attr-info
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
TARGET ClangAttrTokenKinds
TARGET ClangRegularKeywordAttrInfo
)

clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3700,6 +3700,12 @@ def err_sme_definition_using_sm_in_non_sme_target : Error<
"function executed in streaming-SVE mode requires 'sme'">;
def err_sme_definition_using_za_in_non_sme_target : Error<
"function using ZA state requires 'sme'">;
def err_conflicting_attributes_arm_state : Error<
"conflicting attributes for state '%0'">;
def err_unknown_arm_state : Error<
"unknown state '%0'">;
def err_missing_arm_state : Error<
"missing state for %0">;
def err_cconv_change : Error<
"function declared '%0' here was previously declared "
"%select{'%2'|without calling convention}1">;
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,9 @@ KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL)

// Keywords defined by Attr.td.
#ifndef KEYWORD_ATTRIBUTE
#define KEYWORD_ATTRIBUTE(X) KEYWORD(X, KEYALL)
#define KEYWORD_ATTRIBUTE(X, ...) KEYWORD(X, KEYALL)
#endif
#include "clang/Basic/AttrTokenKinds.inc"
#include "clang/Basic/RegularKeywordAttrInfo.inc"

// Clang-specific keywords enabled only in testing.
TESTING_KEYWORD(__unknown_anytype , KEYALL)
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/TokenKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ bool isPragmaAnnotation(TokenKind K);

inline constexpr bool isRegularKeywordAttribute(TokenKind K) {
return (false
#define KEYWORD_ATTRIBUTE(X) || (K == tok::kw_##X)
#include "clang/Basic/AttrTokenKinds.inc"
#define KEYWORD_ATTRIBUTE(X, ...) || (K == tok::kw_##X)
#include "clang/Basic/RegularKeywordAttrInfo.inc"
);
}

Expand Down
17 changes: 9 additions & 8 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -1948,14 +1948,10 @@ def SVBGRP_N : SInst<"svbgrp[_n_{d}]", "dda", "UcUsUiUl", MergeNone, "aarch64_sv
}

let TargetGuard = "sve2p1|sme" in {
def SVPSEL_B : SInst<"svpsel_lane_b8", "PPPm", "Pc", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_H : SInst<"svpsel_lane_b16", "PPPm", "Ps", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_S : SInst<"svpsel_lane_b32", "PPPm", "Pi", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_D : SInst<"svpsel_lane_b64", "PPPm", "Pl", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_COUNT_ALIAS_B : SInst<"svpsel_lane_c8", "}}Pm", "Pc", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_COUNT_ALIAS_H : SInst<"svpsel_lane_c16", "}}Pm", "Ps", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_COUNT_ALIAS_S : SInst<"svpsel_lane_c32", "}}Pm", "Pi", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_COUNT_ALIAS_D : SInst<"svpsel_lane_c64", "}}Pm", "Pl", MergeNone, "", [IsStreamingCompatible], []>;
def SVPSEL_B : SInst<"svpsel_lane_b8", "PPPm", "Pc", MergeNone, "", [IsStreamingOrSVE2p1], []>;
def SVPSEL_H : SInst<"svpsel_lane_b16", "PPPm", "Ps", MergeNone, "", [IsStreamingOrSVE2p1], []>;
def SVPSEL_S : SInst<"svpsel_lane_b32", "PPPm", "Pi", MergeNone, "", [IsStreamingOrSVE2p1], []>;
def SVPSEL_D : SInst<"svpsel_lane_b64", "PPPm", "Pl", MergeNone, "", [IsStreamingOrSVE2p1], []>;
}

// Standalone sve2.1 builtins
Expand All @@ -1979,6 +1975,11 @@ let TargetGuard = "sve2p1|sme2" in {
def SVPEXT_SINGLE : SInst<"svpext_lane_{d}", "P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext", [IsStreamingOrSVE2p1], [ImmCheck<1, ImmCheck0_3>]>;
def SVPEXT_X2 : SInst<"svpext_lane_{d}_x2", "2.P}i", "QcQsQiQl", MergeNone, "aarch64_sve_pext_x2", [IsStreamingOrSVE2p1], [ImmCheck<1, ImmCheck0_1>]>;

def SVPSEL_COUNT_ALIAS_B : SInst<"svpsel_lane_c8", "}}Pm", "Pc", MergeNone, "", [IsStreamingOrSVE2p1], []>;
def SVPSEL_COUNT_ALIAS_H : SInst<"svpsel_lane_c16", "}}Pm", "Ps", MergeNone, "", [IsStreamingOrSVE2p1], []>;
def SVPSEL_COUNT_ALIAS_S : SInst<"svpsel_lane_c32", "}}Pm", "Pi", MergeNone, "", [IsStreamingOrSVE2p1], []>;
def SVPSEL_COUNT_ALIAS_D : SInst<"svpsel_lane_c64", "}}Pm", "Pl", MergeNone, "", [IsStreamingOrSVE2p1], []>;

def SVWHILEGE_COUNT : SInst<"svwhilege_{d}[_{1}]", "}lli", "QcQsQiQl", MergeNone, "aarch64_sve_whilege_{d}", [IsOverloadNone, IsStreamingOrSVE2p1], [ImmCheck<2, ImmCheck2_4_Mul2>]>;
def SVWHILEGT_COUNT : SInst<"svwhilegt_{d}[_{1}]", "}lli", "QcQsQiQl", MergeNone, "aarch64_sve_whilegt_{d}", [IsOverloadNone, IsStreamingOrSVE2p1], [ImmCheck<2, ImmCheck2_4_Mul2>]>;
def SVWHILELE_COUNT : SInst<"svwhilele_{d}[_{1}]", "}lli", "QcQsQiQl", MergeNone, "aarch64_sve_whilele_{d}", [IsOverloadNone, IsStreamingOrSVE2p1], [ImmCheck<2, ImmCheck2_4_Mul2>]>;
Expand Down
44 changes: 22 additions & 22 deletions clang/include/clang/Basic/riscv_vector.td
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ multiclass RVVIndexedLoad<string op> {
defvar eew = eew_list[0];
defvar eew_type = eew_list[1];
let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask",
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>) in {
def: RVVOutOp1Builtin<"v", "vPCe" # eew_type # "Uv", type>;
if !not(IsFloat<type>.val) then {
Expand All @@ -128,7 +128,7 @@ multiclass RVVIndexedLoad<string op> {
defvar eew64 = "64";
defvar eew64_type = "(Log2EEW:6)";
let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh", "RV64"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin", "RV64"],
["RV64"]) in {
def: RVVOutOp1Builtin<"v", "vPCe" # eew64_type # "Uv", type>;
if !not(IsFloat<type>.val) then {
Expand Down Expand Up @@ -222,7 +222,7 @@ multiclass RVVIndexedStore<string op> {
defvar eew = eew_list[0];
defvar eew_type = eew_list[1];
let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask",
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>) in {
def : RVVBuiltin<"v", "0Pe" # eew_type # "Uvv", type>;
if !not(IsFloat<type>.val) then {
Expand All @@ -233,7 +233,7 @@ multiclass RVVIndexedStore<string op> {
defvar eew64 = "64";
defvar eew64_type = "(Log2EEW:6)";
let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh", "RV64"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin", "RV64"],
["RV64"]) in {
def : RVVBuiltin<"v", "0Pe" # eew64_type # "Uvv", type>;
if !not(IsFloat<type>.val) then {
Expand Down Expand Up @@ -681,30 +681,30 @@ let HasBuiltinAlias = false,
def vlm: RVVVLEMaskBuiltin;
defm vle8: RVVVLEBuiltin<["c"]>;
defm vle16: RVVVLEBuiltin<["s"]>;
let Name = "vle16_v", RequiredFeatures = ["ZvfhminOrZvfh"] in
let Name = "vle16_v", RequiredFeatures = ["Zvfhmin"] in
defm vle16_h: RVVVLEBuiltin<["x"]>;
defm vle32: RVVVLEBuiltin<["i","f"]>;
defm vle64: RVVVLEBuiltin<["l","d"]>;

def vsm : RVVVSEMaskBuiltin;
defm vse8 : RVVVSEBuiltin<["c"]>;
defm vse16: RVVVSEBuiltin<["s"]>;
let Name = "vse16_v", RequiredFeatures = ["ZvfhminOrZvfh"] in
let Name = "vse16_v", RequiredFeatures = ["Zvfhmin"] in
defm vse16_h: RVVVSEBuiltin<["x"]>;
defm vse32: RVVVSEBuiltin<["i","f"]>;
defm vse64: RVVVSEBuiltin<["l","d"]>;

// 7.5. Vector Strided Instructions
defm vlse8: RVVVLSEBuiltin<["c"]>;
defm vlse16: RVVVLSEBuiltin<["s"]>;
let Name = "vlse16_v", RequiredFeatures = ["ZvfhminOrZvfh"] in
let Name = "vlse16_v", RequiredFeatures = ["Zvfhmin"] in
defm vlse16_h: RVVVLSEBuiltin<["x"]>;
defm vlse32: RVVVLSEBuiltin<["i","f"]>;
defm vlse64: RVVVLSEBuiltin<["l","d"]>;

defm vsse8 : RVVVSSEBuiltin<["c"]>;
defm vsse16: RVVVSSEBuiltin<["s"]>;
let Name = "vsse16_v", RequiredFeatures = ["ZvfhminOrZvfh"] in
let Name = "vsse16_v", RequiredFeatures = ["Zvfhmin"] in
defm vsse16_h: RVVVSSEBuiltin<["x"]>;
defm vsse32: RVVVSSEBuiltin<["i","f"]>;
defm vsse64: RVVVSSEBuiltin<["l","d"]>;
Expand All @@ -719,7 +719,7 @@ defm : RVVIndexedStore<"vsoxei">;
// 7.7. Unit-stride Fault-Only-First Loads
defm vle8ff: RVVVLEFFBuiltin<["c"]>;
defm vle16ff: RVVVLEFFBuiltin<["s"]>;
let Name = "vle16ff_v", RequiredFeatures = ["ZvfhminOrZvfh"] in
let Name = "vle16ff_v", RequiredFeatures = ["Zvfhmin"] in
defm vle16ff: RVVVLEFFBuiltin<["x"]>;
defm vle32ff: RVVVLEFFBuiltin<["i", "f"]>;
defm vle64ff: RVVVLEFFBuiltin<["l", "d"]>;
Expand All @@ -738,7 +738,7 @@ multiclass RVVUnitStridedSegLoadTuple<string op> {
IRName = op # nf,
MaskedIRName = op # nf # "_mask",
NF = nf,
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>),
ManualCodegen = [{
{
Expand Down Expand Up @@ -800,7 +800,7 @@ multiclass RVVUnitStridedSegStoreTuple<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
HasMaskedOffOperand = false,
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>),
ManualCodegen = [{
{
Expand Down Expand Up @@ -852,7 +852,7 @@ multiclass RVVUnitStridedSegLoadFFTuple<string op> {
IRName = op # nf # "ff",
MaskedIRName = op # nf # "ff_mask",
NF = nf,
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>),
ManualCodegen = [{
{
Expand Down Expand Up @@ -927,7 +927,7 @@ multiclass RVVStridedSegLoadTuple<string op> {
IRName = op # nf,
MaskedIRName = op # nf # "_mask",
NF = nf,
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>),
ManualCodegen = [{
{
Expand Down Expand Up @@ -991,7 +991,7 @@ multiclass RVVStridedSegStoreTuple<string op> {
NF = nf,
HasMaskedOffOperand = false,
MaskedPolicyScheme = NonePolicy,
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>),
ManualCodegen = [{
{
Expand Down Expand Up @@ -1040,7 +1040,7 @@ multiclass RVVIndexedSegLoadTuple<string op> {
IRName = op # nf,
MaskedIRName = op # nf # "_mask",
NF = nf,
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>),
ManualCodegen = [{
{
Expand Down Expand Up @@ -1103,7 +1103,7 @@ multiclass RVVIndexedSegStoreTuple<string op> {
NF = nf,
HasMaskedOffOperand = false,
MaskedPolicyScheme = NonePolicy,
RequiredFeatures = !if(!eq(type, "x"), ["ZvfhminOrZvfh"],
RequiredFeatures = !if(!eq(type, "x"), ["Zvfhmin"],
[]<string>),
ManualCodegen = [{
{
Expand Down Expand Up @@ -1345,7 +1345,7 @@ let HasMasked = false,
[["v", "Uv", "UvUv"]]>;
defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "csilfd",
[["v", "v", "vv"]]>;
let RequiredFeatures = ["ZvfhminOrZvfh"] in
let RequiredFeatures = ["Zvfhmin"] in
defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "x",
[["v", "v", "vv"]]>;
let SupportOverloading = false in
Expand Down Expand Up @@ -1841,7 +1841,7 @@ let HasMasked = false,
}] in {
defm vmerge : RVVOutOp1BuiltinSet<"vmerge", "fd",
[["vvm", "v", "vvvm"]]>;
let RequiredFeatures = ["ZvfhminOrZvfh"] in
let RequiredFeatures = ["Zvfhmin"] in
defm vmerge : RVVOutOp1BuiltinSet<"vmerge", "x",
[["vvm", "v", "vvvm"]]>;
defm vfmerge : RVVOutOp1BuiltinSet<"vfmerge", "xfd",
Expand Down Expand Up @@ -1869,7 +1869,7 @@ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
def vfwcvt_f_xu_v : RVVConvBuiltin<"Fw", "FwUv", "csi", "vfwcvt_f">;
def vfwcvt_f_x_v : RVVConvBuiltin<"Fw", "Fwv", "csi", "vfwcvt_f">;
def vfwcvt_f_f_v : RVVConvBuiltin<"w", "wv", "f", "vfwcvt_f">;
let RequiredFeatures = ["ZvfhminOrZvfh"] in
let RequiredFeatures = ["Zvfhmin"] in
def vfwcvt_f_f_v_fp16 : RVVConvBuiltin<"w", "wv", "x", "vfwcvt_f"> {
let Name = "vfwcvt_f_f_v";
let IRName = "vfwcvt_f_f_v";
Expand Down Expand Up @@ -1966,7 +1966,7 @@ let ManualCodegen = [{
}
let OverloadedName = "vfncvt_f" in {
defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "f", [["v", "vwu"]]>;
let RequiredFeatures = ["ZvfhminOrZvfh"] in
let RequiredFeatures = ["Zvfhmin"] in
defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "x", [["v", "vwu"]]>;
}
}
Expand Down Expand Up @@ -2011,7 +2011,7 @@ let ManualCodegen = [{
}
let OverloadedName = "vfncvt_f" in {
defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "f", [["v", "vw"]]>;
let RequiredFeatures = ["ZvfhminOrZvfh"] in
let RequiredFeatures = ["Zvfhmin"] in
defm : RVVConvBuiltinSet<"vfncvt_f_f_w", "x", [["v", "vw"]]>;
}
}
Expand Down Expand Up @@ -2271,7 +2271,7 @@ let HasMasked = false, HasVL = false, IRName = "" in {
def vreinterpret_u_f : RVVBuiltin<"FvUv", "UvFv", "il", "Uv">;
def vreinterpret_f_i : RVVBuiltin<"vFv", "Fvv", "il", "Fv">;
def vreinterpret_f_u : RVVBuiltin<"UvFv", "FvUv", "il", "Fv">;
let RequiredFeatures = ["ZvfhminOrZvfh"] in {
let RequiredFeatures = ["Zvfhmin"] in {
def vreinterpret_i_h : RVVBuiltin<"Fvv", "vFv", "s", "v">;
def vreinterpret_u_h : RVVBuiltin<"FvUv", "UvFv", "s", "Uv">;
def vreinterpret_h_i : RVVBuiltin<"vFv", "Fvv", "s", "Fv">;
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -5172,7 +5172,7 @@ def module_file_info : Flag<["-"], "module-file-info">, Flags<[]>,
HelpText<"Provide information about a particular module file">;
def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>,
HelpText<"Only supported on AArch64, PowerPC, RISC-V, SystemZ, and X86">;
HelpText<"Only supported on AArch64, PowerPC, RISC-V, SPARC, SystemZ, and X86">;
def multi__module : Flag<["-"], "multi_module">;
def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">;
def multiply__defined : Separate<["-"], "multiply_defined">;
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3398,6 +3398,10 @@ struct FormatStyle {
/// \version 14
unsigned PenaltyBreakOpenParenthesis;

/// The penalty for breaking after ``::``.
/// \version 18
unsigned PenaltyBreakScopeResolution;

/// The penalty for each line break introduced inside a string literal.
/// \version 3.7
unsigned PenaltyBreakString;
Expand Down Expand Up @@ -4873,6 +4877,7 @@ struct FormatStyle {
PenaltyBreakComment == R.PenaltyBreakComment &&
PenaltyBreakFirstLessLess == R.PenaltyBreakFirstLessLess &&
PenaltyBreakOpenParenthesis == R.PenaltyBreakOpenParenthesis &&
PenaltyBreakScopeResolution == R.PenaltyBreakScopeResolution &&
PenaltyBreakString == R.PenaltyBreakString &&
PenaltyBreakTemplateDeclaration ==
R.PenaltyBreakTemplateDeclaration &&
Expand Down
10 changes: 1 addition & 9 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -7110,15 +7110,7 @@ class Sema final {
NestedNameSpecInfo &IdInfo,
bool EnteringContext);

/// The kind of conversion to check for. Either all attributes must match exactly,
/// or the converted type may add/drop '__arm_preserves_za'.
enum class AArch64SMECallConversionKind {
MatchExactly,
MayAddPreservesZA,
MayDropPreservesZA,
};
bool IsInvalidSMECallConversion(QualType FromType, QualType ToType,
AArch64SMECallConversionKind C);
bool IsInvalidSMECallConversion(QualType FromType, QualType ToType);

/// The parser has parsed a nested-name-specifier
/// 'template[opt] template-name < template-args >::'.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Support/RISCVVIntrinsicUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ class RVVIntrinsic {
enum RVVRequire : uint32_t {
RVV_REQ_None = 0,
RVV_REQ_RV64 = 1 << 0,
RVV_REQ_ZvfhminOrZvfh = 1 << 1,
RVV_REQ_Zvfhmin = 1 << 1,
RVV_REQ_Xsfvcp = 1 << 2,
RVV_REQ_Xsfvfnrclipxfqf = 1 << 3,
RVV_REQ_Xsfvfwmaccqqq = 1 << 4,
Expand Down
24 changes: 14 additions & 10 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6280,17 +6280,21 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
D->getTemplatedDecl()))
continue;
if (IsStructuralMatch(D, FoundTemplate)) {
// The Decl in the "From" context has a definition, but in the
// "To" context we already have a definition.
// FIXME Check for ODR error if the two definitions have
// different initializers?
VarTemplateDecl *FoundDef = getTemplateDefinition(FoundTemplate);
if (D->isThisDeclarationADefinition() && FoundDef)
// FIXME Check for ODR error if the two definitions have
// different initializers?
return Importer.MapImported(D, FoundDef);
if (FoundTemplate->getDeclContext()->isRecord() &&
D->getDeclContext()->isRecord())
return Importer.MapImported(D, FoundTemplate);

if (D->getDeclContext()->isRecord()) {
assert(FoundTemplate->getDeclContext()->isRecord() &&
"Member variable template imported as non-member, "
"inconsistent imported AST?");
if (FoundDef)
return Importer.MapImported(D, FoundDef);
if (!D->isThisDeclarationADefinition())
return Importer.MapImported(D, FoundTemplate);
} else {
if (FoundDef && D->isThisDeclarationADefinition())
return Importer.MapImported(D, FoundDef);
}
FoundByLookup = FoundTemplate;
break;
}
Expand Down
20 changes: 16 additions & 4 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15754,10 +15754,22 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
LValue LVal;
LVal.set(VD);

if (!EvaluateInPlace(Value, Info, LVal, this,
/*AllowNonLiteralTypes=*/true) ||
EStatus.HasSideEffects)
return false;
{
// C++23 [intro.execution]/p5
// A full-expression is ... an init-declarator ([dcl.decl]) or a
// mem-initializer.
// So we need to make sure temporary objects are destroyed after having
// evaluated the expression (per C++23 [class.temporary]/p4).
//
// FIXME: Otherwise this may break test/Modules/pr68702.cpp because the
// serialization code calls ParmVarDecl::getDefaultArg() which strips the
// outermost FullExpr, such as ExprWithCleanups.
FullExpressionRAII Scope(Info);
if (!EvaluateInPlace(Value, Info, LVal, this,
/*AllowNonLiteralTypes=*/true) ||
EStatus.HasSideEffects)
return false;
}

// At this point, any lifetime-extended temporaries are completely
// initialized.
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2337,7 +2337,7 @@ bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
auto GlobalIndex = P.getGlobal(VD);
assert(GlobalIndex); // visitVarDecl() didn't return false.
if (VarT) {
if (!this->emitGetGlobal(*VarT, *GlobalIndex, VD))
if (!this->emitGetGlobalUnchecked(*VarT, *GlobalIndex, VD))
return false;
} else {
if (!this->emitGetPtrGlobal(*GlobalIndex, VD))
Expand Down Expand Up @@ -2951,7 +2951,6 @@ bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
/// When calling this, we have a pointer of the local-to-destroy
/// on the stack.
/// Emit destruction of record types (or arrays of record types).
/// FIXME: Handle virtual destructors.
template <class Emitter>
bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Descriptor *Desc) {
assert(Desc);
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/AST/Interp/IntegralAP.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,18 @@ template <bool Signed> class IntegralAP final {
}

static bool rem(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
// FIXME: Implement.
assert(false);
if constexpr (Signed)
*R = IntegralAP(A.V.srem(B.V));
else
*R = IntegralAP(A.V.urem(B.V));
return false;
}

static bool div(IntegralAP A, IntegralAP B, unsigned OpBits, IntegralAP *R) {
// FIXME: Implement.
assert(false);
if constexpr (Signed)
*R = IntegralAP(A.V.sdiv(B.V));
else
*R = IntegralAP(A.V.udiv(B.V));
return false;
}

Expand Down
48 changes: 38 additions & 10 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
return true;
}

static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
const ValueDecl *VD) {
if (!S.getLangOpts().CPlusPlus)
return;

const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc,
VD->getType()->isIntegralOrEnumerationType()
? diag::note_constexpr_ltor_non_const_int
: diag::note_constexpr_ltor_non_constexpr,
1)
<< VD;
S.Note(VD->getLocation(), diag::note_declared_at);
}

static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
if (Ptr.isActive())
Expand Down Expand Up @@ -171,9 +186,7 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {

if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
const auto *VD = Ptr.getDeclDesc()->asValueDecl();
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
S.Note(VD->getLocation(), diag::note_declared_at);
diagnoseNonConstVariable(S, OpPC, VD);
}
return false;
}
Expand Down Expand Up @@ -216,6 +229,24 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return true;
}

bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
assert(Desc);
if (const auto *D = Desc->asValueDecl()) {
if (const auto *VD = dyn_cast<VarDecl>(D);
VD && VD->hasGlobalStorage() &&
!(VD->isConstexpr() || VD->getType().isConstQualified())) {
diagnoseNonConstVariable(S, OpPC, VD);
return false;
}
}

return true;
}

static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return CheckConstant(S, OpPC, Ptr.getDeclDesc());
}

bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return !Ptr.isZero() && !Ptr.isDummy();
}
Expand Down Expand Up @@ -304,6 +335,9 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckLive(S, OpPC, Ptr, AK_Read))
return false;
if (!CheckConstant(S, OpPC, Ptr))
return false;

if (!CheckDummy(S, OpPC, Ptr))
return false;
if (!CheckExtern(S, OpPC, Ptr))
Expand Down Expand Up @@ -605,13 +639,7 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
}
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!VD->getType().isConstQualified()) {
S.FFDiag(E,
VD->getType()->isIntegralOrEnumerationType()
? diag::note_constexpr_ltor_non_const_int
: diag::note_constexpr_ltor_non_constexpr,
1)
<< VD;
S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
diagnoseNonConstVariable(S, OpPC, VD);
return false;
}

Expand Down
14 changes: 14 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
/// Checks if a pointer points to const storage.
bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);

/// Checks if the Descriptor is of a constexpr or const global variable.
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);

/// Checks if a pointer points to a mutable field.
bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);

Expand Down Expand Up @@ -1004,12 +1007,23 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
const Block *B = S.P.getGlobal(I);

if (!CheckConstant(S, OpPC, B->getDescriptor()))
return false;
if (B->isExtern())
return false;
S.Stk.push<T>(B->deref<T>());
return true;
}

/// Same as GetGlobal, but without the checks.
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
auto *B = S.P.getGlobal(I);
S.Stk.push<T>(B->deref<T>());
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
// TODO: emit warning.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ def CheckGlobalCtor : Opcode {}

// [] -> [Value]
def GetGlobal : AccessOpcode;
def GetGlobalUnchecked : AccessOpcode;
// [Value] -> []
def InitGlobal : AccessOpcode;
// [Value] -> []
Expand Down
31 changes: 15 additions & 16 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -937,15 +937,20 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
OS << ')';

FunctionType::ExtInfo Info = T->getExtInfo();
unsigned SMEBits = T->getAArch64SMEAttributes();

if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask))
if (SMEBits & FunctionType::SME_PStateSMCompatibleMask)
OS << " __arm_streaming_compatible";
if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask))
if (SMEBits & FunctionType::SME_PStateSMEnabledMask)
OS << " __arm_streaming";
if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask))
OS << " __arm_shared_za";
if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZAPreservedMask))
OS << " __arm_preserves_za";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Preserves)
OS << " __arm_preserves(\"za\")";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_In)
OS << " __arm_in(\"za\")";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Out)
OS << " __arm_out(\"za\")";
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut)
OS << " __arm_inout(\"za\")";

printFunctionAfter(Info, OS);

Expand Down Expand Up @@ -1788,14 +1793,6 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << "__arm_streaming_compatible";
return;
}
if (T->getAttrKind() == attr::ArmSharedZA) {
OS << "__arm_shared_za";
return;
}
if (T->getAttrKind() == attr::ArmPreservesZA) {
OS << "__arm_preserves_za";
return;
}

OS << " __attribute__((";
switch (T->getAttrKind()) {
Expand Down Expand Up @@ -1839,8 +1836,10 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::WebAssemblyFuncref:
case attr::ArmStreaming:
case attr::ArmStreamingCompatible:
case attr::ArmSharedZA:
case attr::ArmPreservesZA:
case attr::ArmIn:
case attr::ArmOut:
case attr::ArmInOut:
case attr::ArmPreserves:
llvm_unreachable("This attribute should have been handled already");

case attr::NSReturnsRetained:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/PPC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ static void defineXLCompatMacros(MacroBuilder &Builder) {
Builder.defineMacro("__darn_32", "__builtin_darn_32");
Builder.defineMacro("__darn_raw", "__builtin_darn_raw");
Builder.defineMacro("__dcbf", "__builtin_dcbf");
Builder.defineMacro("__fence", "__builtin_ppc_fence");
Builder.defineMacro("__fmadd", "__builtin_fma");
Builder.defineMacro("__fmadds", "__builtin_fmaf");
Builder.defineMacro("__abs", "__builtin_abs");
Expand Down
18 changes: 11 additions & 7 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1767,14 +1767,21 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx,
FPT->isNothrow())
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);

if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask)
unsigned SMEBits = FPT->getAArch64SMEAttributes();
if (SMEBits & FunctionType::SME_PStateSMEnabledMask)
FuncAttrs.addAttribute("aarch64_pstate_sm_enabled");
if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask)
if (SMEBits & FunctionType::SME_PStateSMCompatibleMask)
FuncAttrs.addAttribute("aarch64_pstate_sm_compatible");
if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask)

// ZA
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Out ||
FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_InOut)
FuncAttrs.addAttribute("aarch64_pstate_za_shared");
if (FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_Preserves ||
FunctionType::getArmZAState(SMEBits) == FunctionType::ARM_In) {
FuncAttrs.addAttribute("aarch64_pstate_za_shared");
if (FPT->getAArch64SMEAttributes() & FunctionType::SME_PStateZAPreservedMask)
FuncAttrs.addAttribute("aarch64_pstate_za_preserved");
}
}

static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs,
Expand Down Expand Up @@ -2446,9 +2453,6 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,

if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>())
FuncAttrs.addAttribute("aarch64_pstate_sm_body");

if (TargetDecl->hasAttr<ArmNewZAAttr>())
FuncAttrs.addAttribute("aarch64_pstate_za_new");
}

// Attach "no-builtins" attributes to:
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2380,8 +2380,10 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (D->hasAttr<ArmLocallyStreamingAttr>())
B.addAttribute("aarch64_pstate_sm_body");

if (D->hasAttr<ArmNewZAAttr>())
B.addAttribute("aarch64_pstate_za_new");
if (auto *Attr = D->getAttr<ArmNewAttr>()) {
if (Attr->isNewZA())
B.addAttribute("aarch64_pstate_za_new");
}

// Track whether we need to add the optnone LLVM attribute,
// starting with the default for this optimization level.
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -730,8 +730,8 @@ struct MCDCCoverageBuilder {
return;

// If binary expression is disqualified, don't do mapping.
if (NestLevel.empty() && MCDCBitmapMap.find(CodeGenFunction::stripCond(
E)) == MCDCBitmapMap.end())
if (NestLevel.empty() &&
!MCDCBitmapMap.contains(CodeGenFunction::stripCond(E)))
NotMapped = true;

// Push Stmt on 'NestLevel' stack to keep track of nest location.
Expand All @@ -744,7 +744,7 @@ struct MCDCCoverageBuilder {
// If the operator itself has an assigned ID, this means it represents a
// larger subtree. In this case, pop its ID out of the RHS stack and
// assign that ID to its LHS node. Its RHS will receive a new ID.
if (CondIDs.find(CodeGenFunction::stripCond(E)) != CondIDs.end()) {
if (CondIDs.contains(CodeGenFunction::stripCond(E))) {
// If Stmt has an ID, assign its ID to LHS
CondIDs[CodeGenFunction::stripCond(E->getLHS())] = CondIDs[E];

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,8 @@ template <> struct MappingTraits<FormatStyle> {
Style.PenaltyBreakFirstLessLess);
IO.mapOptional("PenaltyBreakOpenParenthesis",
Style.PenaltyBreakOpenParenthesis);
IO.mapOptional("PenaltyBreakScopeResolution",
Style.PenaltyBreakScopeResolution);
IO.mapOptional("PenaltyBreakString", Style.PenaltyBreakString);
IO.mapOptional("PenaltyBreakTemplateDeclaration",
Style.PenaltyBreakTemplateDeclaration);
Expand Down Expand Up @@ -1602,6 +1604,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;
LLVMStyle.PenaltyBreakBeforeFirstCallParameter = 19;
LLVMStyle.PenaltyBreakOpenParenthesis = 0;
LLVMStyle.PenaltyBreakScopeResolution = 500;
LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational;
LLVMStyle.PenaltyIndentedWhitespace = 0;

Expand Down Expand Up @@ -1698,8 +1701,6 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
/*BasedOnStyle=*/"google",
},
};
GoogleStyle.AttributeMacros.push_back("GUARDED_BY");
GoogleStyle.AttributeMacros.push_back("ABSL_GUARDED_BY");

GoogleStyle.SpacesBeforeTrailingComments = 2;
GoogleStyle.Standard = FormatStyle::LS_Auto;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2209,7 +2209,8 @@ class AnnotatingParser {
(!NextNonComment && !Line.InMacroBody) ||
(NextNonComment &&
(NextNonComment->isPointerOrReference() ||
NextNonComment->isOneOf(tok::identifier, tok::string_literal)))) {
NextNonComment->is(tok::string_literal) ||
(Line.InPragmaDirective && NextNonComment->is(tok::identifier))))) {
return false;
}

Expand Down Expand Up @@ -3765,7 +3766,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
}

if (Left.is(tok::coloncolon))
return 500;
return Style.PenaltyBreakScopeResolution;
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName) ||
Right.is(tok::kw_operator)) {
if (Line.startsWith(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/UnwrappedLineFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class LevelIndentTracker {
/// level to the same indent.
/// Note that \c nextLine must have been called before this method.
void adjustToUnmodifiedLine(const AnnotatedLine &Line) {
if (Line.InPPDirective)
if (Line.InPPDirective || Line.IsContinuation)
return;
assert(Line.Level < IndentForLevel.size());
if (Line.First->is(tok::comment) && IndentForLevel[Line.Level] != -1)
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/CompilerInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2204,7 +2204,7 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc,
// Build the module, inheriting any modules that we've built locally.
if (compileModuleImpl(*this, ImportLoc, ModuleName, Input, StringRef(),
ModuleFileName, PreBuildStep, PostBuildStep)) {
BuiltModules[std::string(ModuleName)] = std::string(ModuleFileName.str());
BuiltModules[std::string(ModuleName)] = std::string(ModuleFileName);
llvm::sys::RemoveFileOnSignal(ModuleFileName);
}
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Frontend/Rewrite/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class FixItActionSuffixInserter : public FixItOptions {
SmallString<128> Path(Filename);
llvm::sys::path::replace_extension(Path,
NewSuffix + llvm::sys::path::extension(Path));
return std::string(Path.str());
return std::string(Path);
}
};

Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6791,7 +6791,13 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
} else if (Tok.isRegularKeywordAttribute()) {
// For consistency with attribute parsing.
Diag(Tok, diag::err_keyword_not_allowed) << Tok.getIdentifierInfo();
bool TakesArgs = doesKeywordAttributeTakeArgs(Tok.getKind());
ConsumeToken();
if (TakesArgs) {
BalancedDelimiterTracker T(*this, tok::l_paren);
if (!T.consumeOpen())
T.skipToEnd();
}
} else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) {
// This declarator is declaring a function, but the requires clause is
// in the wrong place:
Expand Down
24 changes: 21 additions & 3 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1890,7 +1890,13 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
if (!SkipUntil(tok::r_paren, StopAtSemi))
break;
} else if (Tok.isRegularKeywordAttribute()) {
bool TakesArgs = doesKeywordAttributeTakeArgs(Tok.getKind());
ConsumeToken();
if (TakesArgs) {
BalancedDelimiterTracker T(*this, tok::l_paren);
if (!T.consumeOpen())
T.skipToEnd();
}
} else {
break;
}
Expand Down Expand Up @@ -4539,8 +4545,18 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
if (Tok.isRegularKeywordAttribute()) {
SourceLocation Loc = Tok.getLocation();
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, Tok.getKind());
ParsedAttr::Form Form = ParsedAttr::Form(Tok.getKind());
bool TakesArgs = doesKeywordAttributeTakeArgs(Tok.getKind());
ConsumeToken();
if (TakesArgs) {
if (!Tok.is(tok::l_paren))
Diag(Tok.getLocation(), diag::err_expected_lparen_after) << AttrName;
else
ParseAttributeArgsCommon(AttrName, Loc, Attrs, EndLoc,
/*ScopeName*/ nullptr,
/*ScopeLoc*/ Loc, Form);
} else
Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, Form);
return;
}

Expand Down Expand Up @@ -4706,11 +4722,13 @@ SourceLocation Parser::SkipCXX11Attributes() {
T.consumeOpen();
T.skipToEnd();
EndLoc = T.getCloseLocation();
} else if (Tok.isRegularKeywordAttribute()) {
} else if (Tok.isRegularKeywordAttribute() &&
!doesKeywordAttributeTakeArgs(Tok.getKind())) {
EndLoc = Tok.getLocation();
ConsumeToken();
} else {
assert(Tok.is(tok::kw_alignas) && "not an attribute specifier");
assert((Tok.is(tok::kw_alignas) || Tok.isRegularKeywordAttribute()) &&
"not an attribute specifier");
ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (!T.consumeOpen())
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Parse/ParseTentative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,8 @@ bool Parser::TrySkipAttributes() {
// Note that explicitly checking for `[[` and `]]` allows to fail as
// expected in the case of the Objective-C message send syntax.
ConsumeBracket();
} else if (Tok.isRegularKeywordAttribute()) {
} else if (Tok.isRegularKeywordAttribute() &&
!doesKeywordAttributeTakeArgs(Tok.getKind())) {
ConsumeToken();
} else {
ConsumeToken();
Expand Down
27 changes: 18 additions & 9 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3190,11 +3190,15 @@ static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
}

static bool hasSMEZAState(const FunctionDecl *FD) {
if (FD->hasAttr<ArmNewZAAttr>())
return true;
if (const auto *T = FD->getType()->getAs<FunctionProtoType>())
if (T->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask)
if (auto *Attr = FD->getAttr<ArmNewAttr>())
if (Attr->isNewZA())
return true;
if (const auto *T = FD->getType()->getAs<FunctionProtoType>()) {
FunctionType::ArmStateValue State =
FunctionType::getArmZAState(T->getAArch64SMEAttributes());
if (State != FunctionType::ARM_None)
return true;
}
return false;
}

Expand Down Expand Up @@ -7522,14 +7526,19 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,

// If the callee uses AArch64 SME ZA state but the caller doesn't define
// any, then this is an error.
if (ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateZASharedMask) {
FunctionType::ArmStateValue ArmZAState =
FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
if (ArmZAState != FunctionType::ARM_None) {
bool CallerHasZAState = false;
if (const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
if (CallerFD->hasAttr<ArmNewZAAttr>())
auto *Attr = CallerFD->getAttr<ArmNewAttr>();
if (Attr && Attr->isNewZA())
CallerHasZAState = true;
else if (const auto *FPT = CallerFD->getType()->getAs<FunctionProtoType>())
CallerHasZAState = FPT->getExtProtoInfo().AArch64SMEAttributes &
FunctionType::SME_PStateZASharedMask;
else if (const auto *FPT =
CallerFD->getType()->getAs<FunctionProtoType>())
CallerHasZAState = FunctionType::getArmZAState(
FPT->getExtProtoInfo().AArch64SMEAttributes) !=
FunctionType::ARM_None;
}

if (!CallerHasZAState)
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3819,8 +3819,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S,

// It is not permitted to redeclare an SME function with different SME
// attributes.
if (IsInvalidSMECallConversion(Old->getType(), New->getType(),
AArch64SMECallConversionKind::MatchExactly)) {
if (IsInvalidSMECallConversion(Old->getType(), New->getType())) {
Diag(New->getLocation(), diag::err_sme_attr_mismatch)
<< New->getType() << Old->getType();
Diag(OldLocation, diag::note_previous_declaration);
Expand Down Expand Up @@ -12180,13 +12179,15 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Check if the function definition uses any AArch64 SME features without
// having the '+sme' feature enabled.
if (DeclIsDefn) {
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
bool UsesZA = NewFD->hasAttr<ArmNewZAAttr>();
bool UsesZA = Attr && Attr->isNewZA();
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
UsesSM |=
EPI.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
UsesZA |= EPI.AArch64SMEAttributes & FunctionType::SME_PStateZASharedMask;
UsesZA |= FunctionType::getArmZAState(EPI.AArch64SMEAttributes) !=
FunctionType::ARM_None;
}

if (UsesSM || UsesZA) {
Expand Down
78 changes: 63 additions & 15 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8951,26 +8951,74 @@ static bool MustDelayAttributeArguments(const ParsedAttr &AL) {
return false;
}

static bool checkArmNewAttrMutualExclusion(
Sema &S, const ParsedAttr &AL, const FunctionProtoType *FPT,
FunctionType::ArmStateValue CurrentState, StringRef StateName) {
auto CheckForIncompatibleAttr =
[&](FunctionType::ArmStateValue IncompatibleState,
StringRef IncompatibleStateName) {
if (CurrentState == IncompatibleState) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
<< (std::string("'__arm_new(\"") + StateName.str() + "\")'")
<< (std::string("'") + IncompatibleStateName.str() + "(\"" +
StateName.str() + "\")'")
<< true;
AL.setInvalid();
}
};

static void handleArmNewZaAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
if (FPT->getAArch64SMEAttributes() &
FunctionType::SME_PStateZASharedMask) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
<< AL << "'__arm_shared_za'" << true;
CheckForIncompatibleAttr(FunctionType::ARM_In, "__arm_in");
CheckForIncompatibleAttr(FunctionType::ARM_Out, "__arm_out");
CheckForIncompatibleAttr(FunctionType::ARM_InOut, "__arm_inout");
CheckForIncompatibleAttr(FunctionType::ARM_Preserves, "__arm_preserves");
return AL.isInvalid();
}

static void handleArmNewAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.getNumArgs()) {
S.Diag(AL.getLoc(), diag::err_missing_arm_state) << AL;
AL.setInvalid();
return;
}

std::vector<StringRef> NewState;
if (const auto *ExistingAttr = D->getAttr<ArmNewAttr>()) {
for (StringRef S : ExistingAttr->newArgs())
NewState.push_back(S);
}

bool HasZA = false;
for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
StringRef StateName;
SourceLocation LiteralLoc;
if (!S.checkStringLiteralArgumentAttr(AL, I, StateName, &LiteralLoc))
return;

if (StateName == "za")
HasZA = true;
else {
S.Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
AL.setInvalid();
return;
}
if (FPT->getAArch64SMEAttributes() &
FunctionType::SME_PStateZAPreservedMask) {
S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
<< AL << "'__arm_preserves_za'" << true;
AL.setInvalid();

if (std::find(NewState.begin(), NewState.end(), StateName) ==
NewState.end()) { // Avoid adding duplicates.
NewState.push_back(StateName);
}
if (AL.isInvalid())
}

if (auto *FPT = dyn_cast<FunctionProtoType>(D->getFunctionType())) {
FunctionType::ArmStateValue ZAState =
FunctionType::getArmZAState(FPT->getAArch64SMEAttributes());
if (HasZA && ZAState != FunctionType::ARM_None &&
checkArmNewAttrMutualExclusion(S, AL, FPT, ZAState, "za"))
return;
}

handleSimpleAttribute<ArmNewZAAttr>(S, D, AL);
D->dropAttr<ArmNewAttr>();
D->addAttr(::new (S.Context)
ArmNewAttr(S.Context, AL, NewState.data(), NewState.size()));
}

/// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
Expand Down Expand Up @@ -9752,8 +9800,8 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleSimpleAttribute<ArmLocallyStreamingAttr>(S, D, AL);
break;

case ParsedAttr::AT_ArmNewZA:
handleArmNewZaAttr(S, D, AL);
case ParsedAttr::AT_ArmNew:
handleArmNewAttr(S, D, AL);
break;

case ParsedAttr::AT_AcquireHandle:
Expand Down
4 changes: 1 addition & 3 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18328,9 +18328,7 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
}

// SME attributes must match when overriding a function declaration.
if (IsInvalidSMECallConversion(
Old->getType(), New->getType(),
AArch64SMECallConversionKind::MayAddPreservesZA)) {
if (IsInvalidSMECallConversion(Old->getType(), New->getType())) {
Diag(New->getLocation(), diag::err_conflicting_overriding_attributes)
<< New << New->getType() << Old->getType();
Diag(Old->getLocation(), diag::note_overridden_virtual_function);
Expand Down
27 changes: 3 additions & 24 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9803,8 +9803,7 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
}

// Check that the SME attributes for PSTATE.ZA and PSTATE.SM are compatible.
bool Sema::IsInvalidSMECallConversion(QualType FromType, QualType ToType,
AArch64SMECallConversionKind C) {
bool Sema::IsInvalidSMECallConversion(QualType FromType, QualType ToType) {
unsigned FromAttributes = 0, ToAttributes = 0;
if (const auto *FromFn =
dyn_cast<FunctionProtoType>(Context.getCanonicalType(FromType)))
Expand All @@ -9815,25 +9814,7 @@ bool Sema::IsInvalidSMECallConversion(QualType FromType, QualType ToType,
ToAttributes =
ToFn->getAArch64SMEAttributes() & FunctionType::SME_AttributeMask;

if (FromAttributes == ToAttributes)
return false;

// If the '__arm_preserves_za' is the only difference between the types,
// check whether we're allowed to add or remove it.
if ((FromAttributes ^ ToAttributes) ==
FunctionType::SME_PStateZAPreservedMask) {
switch (C) {
case AArch64SMECallConversionKind::MatchExactly:
return true;
case AArch64SMECallConversionKind::MayAddPreservesZA:
return !(ToAttributes & FunctionType::SME_PStateZAPreservedMask);
case AArch64SMECallConversionKind::MayDropPreservesZA:
return !(FromAttributes & FunctionType::SME_PStateZAPreservedMask);
}
}

// There has been a mismatch of attributes
return true;
return FromAttributes != ToAttributes;
}

// Check if we have a conversion between incompatible cmse function pointer
Expand Down Expand Up @@ -10002,9 +9983,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
return Sema::IncompatibleFunctionPointer;
if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans))
return Sema::IncompatibleFunctionPointer;
if (S.IsInvalidSMECallConversion(
rtrans, ltrans,
Sema::AArch64SMECallConversionKind::MayDropPreservesZA))
if (S.IsInvalidSMECallConversion(rtrans, ltrans))
return Sema::IncompatibleFunctionPointer;
return ConvTy;
}
Expand Down
20 changes: 0 additions & 20 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1784,26 +1784,6 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType,
Changed = true;
}

// Drop the 'arm_preserves_za' if not present in the target type (we can do
// that because it is merely a hint).
if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) {
FunctionProtoType::ExtProtoInfo ExtInfo = FromFPT->getExtProtoInfo();
if (ExtInfo.AArch64SMEAttributes &
FunctionType::SME_PStateZAPreservedMask) {
unsigned ToFlags = 0;
if (const auto *ToFPT = dyn_cast<FunctionProtoType>(ToFn))
ToFlags = ToFPT->getExtProtoInfo().AArch64SMEAttributes;
if (!(ToFlags & FunctionType::SME_PStateZAPreservedMask)) {
ExtInfo.setArmSMEAttribute(FunctionType::SME_PStateZAPreservedMask,
false);
QualType QT = Context.getFunctionType(
FromFPT->getReturnType(), FromFPT->getParamTypes(), ExtInfo);
FromFn = QT->getAs<FunctionType>();
Changed = true;
}
}
}

// Drop 'noexcept' if not present in target type.
if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) {
const auto *ToFPT = cast<FunctionProtoType>(ToFn);
Expand Down
5 changes: 2 additions & 3 deletions clang/lib/Sema/SemaRISCVVectorLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,8 @@ void RISCVIntrinsicManagerImpl::ConstructRVVIntrinsics(
continue;

if (BaseType == BasicType::Float16) {
if ((Record.RequiredExtensions & RVV_REQ_ZvfhminOrZvfh) ==
RVV_REQ_ZvfhminOrZvfh) {
if (!TI.hasFeature("zvfh") && !TI.hasFeature("zvfhmin"))
if ((Record.RequiredExtensions & RVV_REQ_Zvfhmin) == RVV_REQ_Zvfhmin) {
if (!TI.hasFeature("zvfhmin"))
continue;
} else if (!TI.hasFeature("zvfh")) {
continue;
Expand Down
80 changes: 71 additions & 9 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
case ParsedAttr::AT_CmseNSCall: \
case ParsedAttr::AT_ArmStreaming: \
case ParsedAttr::AT_ArmStreamingCompatible: \
case ParsedAttr::AT_ArmSharedZA: \
case ParsedAttr::AT_ArmPreservesZA: \
case ParsedAttr::AT_ArmPreserves: \
case ParsedAttr::AT_ArmIn: \
case ParsedAttr::AT_ArmOut: \
case ParsedAttr::AT_ArmInOut: \
case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \
case ParsedAttr::AT_AnyX86NoCfCheck: \
CALLING_CONV_ATTRS_CASELIST
Expand Down Expand Up @@ -7876,6 +7878,49 @@ static bool checkMutualExclusion(TypeProcessingState &state,
return true;
}

static bool handleArmStateAttribute(Sema &S,
FunctionProtoType::ExtProtoInfo &EPI,
ParsedAttr &Attr,
FunctionType::ArmStateValue State) {
if (!Attr.getNumArgs()) {
S.Diag(Attr.getLoc(), diag::err_missing_arm_state) << Attr;
Attr.setInvalid();
return true;
}

for (unsigned I = 0; I < Attr.getNumArgs(); ++I) {
StringRef StateName;
SourceLocation LiteralLoc;
if (!S.checkStringLiteralArgumentAttr(Attr, I, StateName, &LiteralLoc))
return true;

unsigned Shift;
FunctionType::ArmStateValue ExistingState;
if (StateName == "za") {
Shift = FunctionType::SME_ZAShift;
ExistingState = FunctionType::getArmZAState(EPI.AArch64SMEAttributes);
} else {
S.Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName;
Attr.setInvalid();
return true;
}

// __arm_in(S), __arm_out(S), __arm_inout(S) and __arm_preserves(S)
// are all mutually exclusive for the same S, so check if there are
// conflicting attributes.
if (ExistingState != FunctionType::ARM_None && ExistingState != State) {
S.Diag(LiteralLoc, diag::err_conflicting_attributes_arm_state)
<< StateName;
Attr.setInvalid();
return true;
}

EPI.setArmSMEAttribute(
(FunctionType::AArch64SMETypeAttributes)((State << Shift)));
}
return false;
}

/// Process an individual function attribute. Returns true to
/// indicate that the attribute was handled, false if it wasn't.
static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
Expand Down Expand Up @@ -8008,11 +8053,18 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,

if (attr.getKind() == ParsedAttr::AT_ArmStreaming ||
attr.getKind() == ParsedAttr::AT_ArmStreamingCompatible ||
attr.getKind() == ParsedAttr::AT_ArmSharedZA ||
attr.getKind() == ParsedAttr::AT_ArmPreservesZA){
if (S.CheckAttrTarget(attr) || S.CheckAttrNoArgs(attr))
attr.getKind() == ParsedAttr::AT_ArmPreserves ||
attr.getKind() == ParsedAttr::AT_ArmIn ||
attr.getKind() == ParsedAttr::AT_ArmOut ||
attr.getKind() == ParsedAttr::AT_ArmInOut) {
if (S.CheckAttrTarget(attr))
return true;

if (attr.getKind() == ParsedAttr::AT_ArmStreaming ||
attr.getKind() == ParsedAttr::AT_ArmStreamingCompatible)
if (S.CheckAttrNoArgs(attr))
return true;

if (!unwrapped.isFunctionType())
return false;

Expand All @@ -8039,11 +8091,21 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
return true;
EPI.setArmSMEAttribute(FunctionType::SME_PStateSMCompatibleMask);
break;
case ParsedAttr::AT_ArmSharedZA:
EPI.setArmSMEAttribute(FunctionType::SME_PStateZASharedMask);
case ParsedAttr::AT_ArmPreserves:
if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_Preserves))
return true;
break;
case ParsedAttr::AT_ArmIn:
if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_In))
return true;
break;
case ParsedAttr::AT_ArmPreservesZA:
EPI.setArmSMEAttribute(FunctionType::SME_PStateZAPreservedMask);
case ParsedAttr::AT_ArmOut:
if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_Out))
return true;
break;
case ParsedAttr::AT_ArmInOut:
if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_InOut))
return true;
break;
default:
llvm_unreachable("Unsupported attribute");
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1897,7 +1897,8 @@ namespace {

unsigned char Flags = (Data.AlreadyIncluded << 6)
| (Data.HFI.isImport << 5)
| (Data.HFI.isPragmaOnce << 4)
| (Writer.isWritingStdCXXNamedModules() ? 0 :
Data.HFI.isPragmaOnce << 4)
| (Data.HFI.DirInfo << 1)
| Data.HFI.IndexHeaderMapHeader;
LE.write<uint8_t>(Flags);
Expand Down
32 changes: 32 additions & 0 deletions clang/test/AST/Interp/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,3 +566,35 @@ namespace GH69115 {
static_assert(foo2() == 0, "");
#endif
}

namespace NonConstReads {
#if __cplusplus >= 202002L
void *p = nullptr; // ref-note {{declared here}} \
// expected-note {{declared here}}

int arr[!p]; // ref-error {{not allowed at file scope}} \
// expected-error {{not allowed at file scope}} \
// ref-warning {{variable length arrays}} \
// ref-note {{read of non-constexpr variable 'p'}} \
// expected-warning {{variable length arrays}} \
// expected-note {{read of non-constexpr variable 'p'}}
int z; // ref-note {{declared here}} \
// expected-note {{declared here}}
int a[z]; // ref-error {{not allowed at file scope}} \
// expected-error {{not allowed at file scope}} \
// ref-warning {{variable length arrays}} \
// ref-note {{read of non-const variable 'z'}} \
// expected-warning {{variable length arrays}} \
// expected-note {{read of non-const variable 'z'}}
#else
void *p = nullptr;
int arr[!p]; // ref-error {{not allowed at file scope}} \
// expected-error {{not allowed at file scope}}
int z;
int a[z]; // ref-error {{not allowed at file scope}} \
// expected-error {{not allowed at file scope}}
#endif

const int y = 0;
int yy[y];
}
22 changes: 16 additions & 6 deletions clang/test/AST/Interp/cxx23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,32 @@ constexpr int g(int n) { // ref20-error {{constexpr function never produc
}

constexpr int c_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
// ref23-error {{constexpr function never produces a constant expression}} \
// expected20-error {{constexpr function never produces a constant expression}} \
// expected23-error {{constexpr function never produces a constant expression}}
static _Thread_local int m = 0; // ref20-note {{control flows through the definition of a thread_local variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a thread_local variable}} \
// expected20-warning {{is a C++23 extension}}
return m;
// expected20-warning {{is a C++23 extension}} \
// expected20-note {{declared here}} \
// expected23-note {{declared here}}
return m; // expected20-note {{read of non-const variable}} \
// expected23-note {{read of non-const variable}}
}


constexpr int gnu_thread_local(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
// ref23-error {{constexpr function never produces a constant expression}}
// ref23-error {{constexpr function never produces a constant expression}} \
// expected20-error {{constexpr function never produces a constant expression}} \
// expected23-error {{constexpr function never produces a constant expression}}
static __thread int m = 0; // ref20-note {{control flows through the definition of a thread_local variable}} \
// ref20-warning {{is a C++23 extension}} \
// ref23-note {{control flows through the definition of a thread_local variable}} \
// expected20-warning {{is a C++23 extension}}
return m;
// expected20-warning {{is a C++23 extension}} \
// expected20-note {{declared here}} \
// expected23-note {{declared here}}
return m; // expected20-note {{read of non-const variable}} \
// expected23-note {{read of non-const variable}}
}

constexpr int h(int n) { // ref20-error {{constexpr function never produces a constant expression}} \
Expand Down
Loading