226 changes: 135 additions & 91 deletions clang-tools-extra/clang-tidy/modernize/UseStartsEndsWithCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "UseStartsEndsWithCheck.h"

#include "../utils/ASTUtils.h"
#include "../utils/OptionsUtils.h"
#include "clang/Lex/Lexer.h"

Expand All @@ -16,13 +17,71 @@
using namespace clang::ast_matchers;

namespace clang::tidy::modernize {
struct NotLengthExprForStringNode {
NotLengthExprForStringNode(std::string ID, DynTypedNode Node,
ASTContext *Context)
: ID(std::move(ID)), Node(std::move(Node)), Context(Context) {}
bool operator()(const internal::BoundNodesMap &Nodes) const {
// Match a string literal and an integer size or strlen() call.
if (const auto *StringLiteralNode = Nodes.getNodeAs<StringLiteral>(ID)) {
if (const auto *IntegerLiteralSizeNode = Node.get<IntegerLiteral>()) {
return StringLiteralNode->getLength() !=
IntegerLiteralSizeNode->getValue().getZExtValue();
}

if (const auto *StrlenNode = Node.get<CallExpr>()) {
if (StrlenNode->getDirectCallee()->getName() != "strlen" ||
StrlenNode->getNumArgs() != 1) {
return true;
}

if (const auto *StrlenArgNode = dyn_cast<StringLiteral>(
StrlenNode->getArg(0)->IgnoreParenImpCasts())) {
return StrlenArgNode->getLength() != StringLiteralNode->getLength();
}
}
}

// Match a string variable and a call to length() or size().
if (const auto *ExprNode = Nodes.getNodeAs<Expr>(ID)) {
if (const auto *MemberCallNode = Node.get<CXXMemberCallExpr>()) {
const CXXMethodDecl *MethodDeclNode = MemberCallNode->getMethodDecl();
const StringRef Name = MethodDeclNode->getName();
if (!MethodDeclNode->isConst() || MethodDeclNode->getNumParams() != 0 ||
(Name != "size" && Name != "length")) {
return true;
}

if (const auto *OnNode =
dyn_cast<Expr>(MemberCallNode->getImplicitObjectArgument())) {
return !utils::areStatementsIdentical(OnNode->IgnoreParenImpCasts(),
ExprNode->IgnoreParenImpCasts(),
*Context);
}
}
}

return true;
}

private:
std::string ID;
DynTypedNode Node;
ASTContext *Context;
};

AST_MATCHER_P(Expr, lengthExprForStringNode, std::string, ID) {
return Builder->removeBindings(NotLengthExprForStringNode(
ID, DynTypedNode::create(Node), &(Finder->getASTContext())));
}

UseStartsEndsWithCheck::UseStartsEndsWithCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}

void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
const auto ZeroLiteral = integerLiteral(equals(0));

const auto HasStartsWithMethodWithName = [](const std::string &Name) {
return hasMethod(
cxxMethodDecl(hasName(Name), isConst(), parameterCountIs(1))
Expand All @@ -32,119 +91,104 @@ void UseStartsEndsWithCheck::registerMatchers(MatchFinder *Finder) {
anyOf(HasStartsWithMethodWithName("starts_with"),
HasStartsWithMethodWithName("startsWith"),
HasStartsWithMethodWithName("startswith"));
const auto ClassWithStartsWithFunction = cxxRecordDecl(anyOf(
HasStartsWithMethod, hasAnyBase(hasType(hasCanonicalType(hasDeclaration(
cxxRecordDecl(HasStartsWithMethod)))))));
const auto OnClassWithStartsWithFunction =
on(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
anyOf(HasStartsWithMethod,
hasAnyBase(hasType(hasCanonicalType(
hasDeclaration(cxxRecordDecl(HasStartsWithMethod)))))))))));

const auto HasEndsWithMethodWithName = [](const std::string &Name) {
return hasMethod(
cxxMethodDecl(hasName(Name), isConst(), parameterCountIs(1))
.bind("ends_with_fun"));
};
const auto HasEndsWithMethod = anyOf(HasEndsWithMethodWithName("ends_with"),
HasEndsWithMethodWithName("endsWith"),
HasEndsWithMethodWithName("endswith"));
const auto OnClassWithEndsWithFunction =
on(expr(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
anyOf(HasEndsWithMethod,
hasAnyBase(hasType(hasCanonicalType(hasDeclaration(
cxxRecordDecl(HasEndsWithMethod)))))))))))
.bind("haystack"));

// Case 1: X.find(Y) [!=]= 0 -> starts_with.
const auto FindExpr = cxxMemberCallExpr(
// A method call with no second argument or the second argument is zero...
anyOf(argumentCountIs(1), hasArgument(1, ZeroLiteral)),
// ... named find...
callee(cxxMethodDecl(hasName("find")).bind("find_fun")),
// ... on a class with a starts_with function.
on(hasType(
hasCanonicalType(hasDeclaration(ClassWithStartsWithFunction)))),
// Bind search expression.
hasArgument(0, expr().bind("search_expr")));
OnClassWithStartsWithFunction, hasArgument(0, expr().bind("needle")));

// Case 2: X.rfind(Y, 0) [!=]= 0 -> starts_with.
const auto RFindExpr = cxxMemberCallExpr(
// A method call with a second argument of zero...
hasArgument(1, ZeroLiteral),
// ... named rfind...
callee(cxxMethodDecl(hasName("rfind")).bind("find_fun")),
// ... on a class with a starts_with function.
on(hasType(
hasCanonicalType(hasDeclaration(ClassWithStartsWithFunction)))),
// Bind search expression.
hasArgument(0, expr().bind("search_expr")));

// Match a string literal and an integer or strlen() call matching the length.
const auto HasStringLiteralAndLengthArgs = [](const auto StringArgIndex,
const auto LengthArgIndex) {
return allOf(
hasArgument(StringArgIndex, stringLiteral().bind("string_literal_arg")),
hasArgument(LengthArgIndex,
anyOf(integerLiteral().bind("integer_literal_size_arg"),
callExpr(callee(functionDecl(parameterCountIs(1),
hasName("strlen"))),
hasArgument(0, stringLiteral().bind(
"strlen_arg"))))));
};

// Match a string variable and a call to length() or size().
const auto HasStringVariableAndSizeCallArgs = [](const auto StringArgIndex,
const auto LengthArgIndex) {
return allOf(
hasArgument(StringArgIndex, declRefExpr(hasDeclaration(
decl().bind("string_var_decl")))),
hasArgument(LengthArgIndex,
cxxMemberCallExpr(
callee(cxxMethodDecl(isConst(), parameterCountIs(0),
hasAnyName("size", "length"))),
on(declRefExpr(
to(decl(equalsBoundNode("string_var_decl"))))))));
};

// Match either one of the two cases above.
const auto HasStringAndLengthArgs =
[HasStringLiteralAndLengthArgs, HasStringVariableAndSizeCallArgs](
const auto StringArgIndex, const auto LengthArgIndex) {
return anyOf(
HasStringLiteralAndLengthArgs(StringArgIndex, LengthArgIndex),
HasStringVariableAndSizeCallArgs(StringArgIndex, LengthArgIndex));
};
OnClassWithStartsWithFunction, hasArgument(0, expr().bind("needle")));

// Case 3: X.compare(0, LEN(Y), Y) [!=]= 0 -> starts_with.
const auto CompareExpr = cxxMemberCallExpr(
// A method call with three arguments...
argumentCountIs(3),
// ... where the first argument is zero...
hasArgument(0, ZeroLiteral),
// ... named compare...
argumentCountIs(3), hasArgument(0, ZeroLiteral),
callee(cxxMethodDecl(hasName("compare")).bind("find_fun")),
// ... on a class with a starts_with function...
on(hasType(
hasCanonicalType(hasDeclaration(ClassWithStartsWithFunction)))),
// ... where the third argument is some string and the second a length.
HasStringAndLengthArgs(2, 1),
// Bind search expression.
hasArgument(2, expr().bind("search_expr")));
OnClassWithStartsWithFunction, hasArgument(2, expr().bind("needle")),
hasArgument(1, lengthExprForStringNode("needle")));

// Case 4: X.compare(LEN(X) - LEN(Y), LEN(Y), Y) [!=]= 0 -> ends_with.
const auto CompareEndsWithExpr = cxxMemberCallExpr(
argumentCountIs(3),
callee(cxxMethodDecl(hasName("compare")).bind("find_fun")),
OnClassWithEndsWithFunction, hasArgument(2, expr().bind("needle")),
hasArgument(1, lengthExprForStringNode("needle")),
hasArgument(0,
binaryOperator(hasOperatorName("-"),
hasLHS(lengthExprForStringNode("haystack")),
hasRHS(lengthExprForStringNode("needle")))));

// All cases comparing to 0.
Finder->addMatcher(
// Match [=!]= with a zero on one side and (r?)find|compare on the other.
binaryOperator(
hasAnyOperatorName("==", "!="),
hasOperands(cxxMemberCallExpr(anyOf(FindExpr, RFindExpr, CompareExpr))
hasOperands(cxxMemberCallExpr(anyOf(FindExpr, RFindExpr, CompareExpr,
CompareEndsWithExpr))
.bind("find_expr"),
ZeroLiteral))
.bind("expr"),
this);

// Case 5: X.rfind(Y) [!=]= LEN(X) - LEN(Y) -> ends_with.
Finder->addMatcher(
binaryOperator(
hasAnyOperatorName("==", "!="),
hasOperands(
cxxMemberCallExpr(
anyOf(
argumentCountIs(1),
allOf(argumentCountIs(2),
hasArgument(
1,
anyOf(declRefExpr(to(varDecl(hasName("npos")))),
memberExpr(member(hasName("npos"))))))),
callee(cxxMethodDecl(hasName("rfind")).bind("find_fun")),
OnClassWithEndsWithFunction,
hasArgument(0, expr().bind("needle")))
.bind("find_expr"),
binaryOperator(hasOperatorName("-"),
hasLHS(lengthExprForStringNode("haystack")),
hasRHS(lengthExprForStringNode("needle")))))
.bind("expr"),
this);
}

void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {
const auto *ComparisonExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
const auto *FindExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>("find_expr");
const auto *FindFun = Result.Nodes.getNodeAs<CXXMethodDecl>("find_fun");
const auto *SearchExpr = Result.Nodes.getNodeAs<Expr>("search_expr");
const auto *SearchExpr = Result.Nodes.getNodeAs<Expr>("needle");
const auto *StartsWithFunction =
Result.Nodes.getNodeAs<CXXMethodDecl>("starts_with_fun");

const auto *StringLiteralArg =
Result.Nodes.getNodeAs<StringLiteral>("string_literal_arg");
const auto *IntegerLiteralSizeArg =
Result.Nodes.getNodeAs<IntegerLiteral>("integer_literal_size_arg");
const auto *StrlenArg = Result.Nodes.getNodeAs<StringLiteral>("strlen_arg");

// Filter out compare cases where the length does not match string literal.
if (StringLiteralArg && IntegerLiteralSizeArg &&
StringLiteralArg->getLength() !=
IntegerLiteralSizeArg->getValue().getZExtValue()) {
return;
}

if (StringLiteralArg && StrlenArg &&
StringLiteralArg->getLength() != StrlenArg->getLength()) {
return;
}
const auto *EndsWithFunction =
Result.Nodes.getNodeAs<CXXMethodDecl>("ends_with_fun");
assert(bool(StartsWithFunction) != bool(EndsWithFunction));
const CXXMethodDecl *ReplacementFunction =
StartsWithFunction ? StartsWithFunction : EndsWithFunction;

if (ComparisonExpr->getBeginLoc().isMacroID()) {
return;
Expand All @@ -154,26 +198,26 @@ void UseStartsEndsWithCheck::check(const MatchFinder::MatchResult &Result) {

auto Diagnostic =
diag(FindExpr->getExprLoc(), "use %0 instead of %1() %select{==|!=}2 0")
<< StartsWithFunction->getName() << FindFun->getName() << Neg;
<< ReplacementFunction->getName() << FindFun->getName() << Neg;

// Remove possible arguments after search expression and ' [!=]= 0' suffix.
// Remove possible arguments after search expression and ' [!=]= .+' suffix.
Diagnostic << FixItHint::CreateReplacement(
CharSourceRange::getTokenRange(
Lexer::getLocForEndOfToken(SearchExpr->getEndLoc(), 0,
*Result.SourceManager, getLangOpts()),
ComparisonExpr->getEndLoc()),
")");

// Remove possible '0 [!=]= ' prefix.
// Remove possible '.+ [!=]= ' prefix.
Diagnostic << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
ComparisonExpr->getBeginLoc(), FindExpr->getBeginLoc()));

// Replace method name by 'starts_with'.
// Replace method name by '(starts|ends)_with'.
// Remove possible arguments before search expression.
Diagnostic << FixItHint::CreateReplacement(
CharSourceRange::getCharRange(FindExpr->getExprLoc(),
SearchExpr->getBeginLoc()),
(StartsWithFunction->getName() + "(").str());
(ReplacementFunction->getName() + "(").str());

// Add possible negation '!'.
if (Neg) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace clang::tidy::modernize {

/// Checks for common roundabout ways to express ``starts_with`` and
/// ``ends_with`` and suggests replacing with ``starts_with`` when the method is
/// ``ends_with`` and suggests replacing with the simpler method when it is
/// available. Notably, this will work with ``std::string`` and
/// ``std::string_view``.
///
Expand Down
7 changes: 6 additions & 1 deletion clang-tools-extra/clangd/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,13 @@ getQualification(ASTContext &Context, const DeclContext *DestContext,
// since we stored inner-most parent first.
std::string Result;
llvm::raw_string_ostream OS(Result);
for (const auto *Parent : llvm::reverse(Parents))
for (const auto *Parent : llvm::reverse(Parents)) {
if (Parent != *Parents.rbegin() && Parent->isDependent() &&
Parent->getAsRecordDecl() &&
Parent->getAsRecordDecl()->getDescribedClassTemplate())
OS << "template ";
Parent->print(OS, Context.getPrintingPolicy());
}
return OS.str();
}

Expand Down
50 changes: 44 additions & 6 deletions clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,28 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
SM.getBufferData(SM.getMainFileID()), Replacements);
if (!QualifiedFunc)
return QualifiedFunc.takeError();
return QualifiedFunc->substr(FuncBegin, FuncEnd - FuncBegin + 1);

std::string TemplatePrefix;
if (auto *MD = llvm::dyn_cast<CXXMethodDecl>(FD)) {
for (const CXXRecordDecl *Parent = MD->getParent(); Parent;
Parent =
llvm::dyn_cast_or_null<const CXXRecordDecl>(Parent->getParent())) {
if (const TemplateParameterList *Params =
Parent->getDescribedTemplateParams()) {
std::string S;
llvm::raw_string_ostream Stream(S);
Params->print(Stream, FD->getASTContext());
if (!S.empty())
*S.rbegin() = '\n'; // Replace space with newline
TemplatePrefix.insert(0, S);
}
}
}

auto Source = QualifiedFunc->substr(FuncBegin, FuncEnd - FuncBegin + 1);
if (!TemplatePrefix.empty())
Source.insert(0, TemplatePrefix);
return Source;
}

// Returns replacements to delete tokens with kind `Kind` in the range
Expand Down Expand Up @@ -212,9 +233,13 @@ getFunctionSourceCode(const FunctionDecl *FD, const DeclContext *TargetContext,
}
}
const NamedDecl *ND = Ref.Targets.front();
const std::string Qualifier =
std::string Qualifier =
getQualification(AST, TargetContext,
SM.getLocForStartOfFile(SM.getMainFileID()), ND);
if (ND->getDeclContext()->isDependentContext() &&
llvm::isa<TypeDecl>(ND)) {
Qualifier.insert(0, "typename ");
}
if (auto Err = DeclarationCleanups.add(
tooling::Replacement(SM, Ref.NameLoc, 0, Qualifier)))
Errors = llvm::joinErrors(std::move(Errors), std::move(Err));
Expand Down Expand Up @@ -407,10 +432,23 @@ class DefineOutline : public Tweak {
return !SameFile;
}

// Bail out in templated classes, as it is hard to spell the class name,
// i.e if the template parameter is unnamed.
if (MD->getParent()->isTemplated())
return false;
for (const CXXRecordDecl *Parent = MD->getParent(); Parent;
Parent =
llvm::dyn_cast_or_null<const CXXRecordDecl>(Parent->getParent())) {
if (const TemplateParameterList *Params =
Parent->getDescribedTemplateParams()) {

// Class template member functions must be defined in the
// same file.
SameFile = true;

// Bail out if the template parameter is unnamed.
for (NamedDecl *P : *Params) {
if (!P->getIdentifier())
return false;
}
}
}

// The refactoring is meaningless for unnamed classes and namespaces,
// unless we're outlining in the same file
Expand Down
55 changes: 42 additions & 13 deletions clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ TEST_F(DefineOutlineTest, TriggersOnFunctionDecl) {
F^oo(const Foo&) = delete;
};)cpp");

// Not available within templated classes, as it is hard to spell class name
// out-of-line in such cases.
// Not available within templated classes with unnamed parameters, as it is
// hard to spell class name out-of-line in such cases.
EXPECT_UNAVAILABLE(R"cpp(
template <typename> struct Foo { void fo^o(){} };
)cpp");
Expand Down Expand Up @@ -154,7 +154,6 @@ TEST_F(DefineOutlineTest, FailsWithoutSource) {
}

TEST_F(DefineOutlineTest, ApplyTest) {
llvm::StringMap<std::string> EditedFiles;
ExtraFiles["Test.cpp"] = "";
FileName = "Test.hpp";

Expand Down Expand Up @@ -229,17 +228,18 @@ TEST_F(DefineOutlineTest, ApplyTest) {
// Ctor initializer with attribute.
{
R"cpp(
class Foo {
F^oo(int z) __attribute__((weak)) : bar(2){}
template <typename T> class Foo {
F^oo(T z) __attribute__((weak)) : bar(2){}
int bar;
};)cpp",
R"cpp(
class Foo {
Foo(int z) __attribute__((weak)) ;
template <typename T> class Foo {
Foo(T z) __attribute__((weak)) ;
int bar;
};)cpp",
"Foo::Foo(int z) __attribute__((weak)) : bar(2){}\n",
},
};template <typename T>
Foo<T>::Foo(T z) __attribute__((weak)) : bar(2){}
)cpp",
""},
// Virt specifiers.
{
R"cpp(
Expand Down Expand Up @@ -369,7 +369,31 @@ TEST_F(DefineOutlineTest, ApplyTest) {
};)cpp",
" void A::foo(int) {}\n",
},
// Destrctors
// Complex class template
{
R"cpp(
template <typename T, typename ...U> struct O1 {
template <class V, int A> struct O2 {
enum E { E1, E2 };
struct I {
E f^oo(T, U..., V, E) { return E1; }
};
};
};)cpp",
R"cpp(
template <typename T, typename ...U> struct O1 {
template <class V, int A> struct O2 {
enum E { E1, E2 };
struct I {
E foo(T, U..., V, E) ;
};
};
};template <typename T, typename ...U>
template <class V, int A>
typename O1<T, U...>::template O2<V, A>::E O1<T, U...>::template O2<V, A>::I::foo(T, U..., V, E) { return E1; }
)cpp",
""},
// Destructors
{
"class A { ~A^(){} };",
"class A { ~A(); };",
Expand All @@ -378,9 +402,14 @@ TEST_F(DefineOutlineTest, ApplyTest) {
};
for (const auto &Case : Cases) {
SCOPED_TRACE(Case.Test);
llvm::StringMap<std::string> EditedFiles;
EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader);
EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
testPath("Test.cpp"), Case.ExpectedSource)));
if (Case.ExpectedSource.empty()) {
EXPECT_TRUE(EditedFiles.empty());
} else {
EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
testPath("Test.cpp"), Case.ExpectedSource)));
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ Objective-C
Miscellaneous
^^^^^^^^^^^^^

- The DefineOutline tweak now handles member functions of class templates.

Improvements to clang-doc
-------------------------

Expand Down Expand Up @@ -202,6 +204,10 @@ Changes in existing checks
<clang-tidy/checks/modernize/use-nullptr>` check to also recognize
``NULL``/``__null`` (but not ``0``) when used with a templated type.

- Improved :doc:`modernize-use-starts-ends-with
<clang-tidy/checks/modernize/use-starts-ends-with>` check to handle two cases
that can be replaced with ``ends_with``

- Improved :doc:`modernize-use-std-format
<clang-tidy/checks/modernize/use-std-format>` check to support replacing
member function calls too and to only expand macros starting with ``PRI``
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ modernize-use-starts-ends-with
==============================

Checks for common roundabout ways to express ``starts_with`` and ``ends_with``
and suggests replacing with ``starts_with`` when the method is available.
Notably, this will work with ``std::string`` and ``std::string_view``.
and suggests replacing with the simpler method when it is available. Notably,
this will work with ``std::string`` and ``std::string_view``.

.. code-block:: c++

std::string s = "...";
if (s.find("prefix") == 0) { /* do something */ }
if (s.rfind("prefix", 0) == 0) { /* do something */ }
if (s.compare(0, strlen("prefix"), "prefix") == 0) { /* do something */ }
if (s.compare(s.size() - strlen("suffix"), strlen("suffix"), "suffix") == 0) {
/* do something */
}
if (s.rfind("suffix") == (s.length() - 6)) {
/* do something */
}
becomes

Expand All @@ -22,3 +28,5 @@ becomes
if (s.starts_with("prefix")) { /* do something */ }
if (s.starts_with("prefix")) { /* do something */ }
if (s.starts_with("prefix")) { /* do something */ }
if (s.ends_with("suffix")) { /* do something */ }
if (s.ends_with("suffix")) { /* do something */ }
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ struct basic_string {
constexpr bool starts_with(C ch) const noexcept;
constexpr bool starts_with(const C* s) const;

constexpr bool ends_with(std::basic_string_view<C, T> sv) const noexcept;
constexpr bool ends_with(C ch) const noexcept;
constexpr bool ends_with(const C* s) const;

_Type& operator[](size_type);
const _Type& operator[](size_type) const;

Expand Down Expand Up @@ -108,6 +112,10 @@ struct basic_string_view {
constexpr bool starts_with(C ch) const noexcept;
constexpr bool starts_with(const C* s) const;

constexpr bool ends_with(basic_string_view sv) const noexcept;
constexpr bool ends_with(C ch) const noexcept;
constexpr bool ends_with(const C* s) const;

constexpr int compare(basic_string_view sv) const noexcept;

static constexpr size_t npos = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,62 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use starts_with
// CHECK-FIXES: !s.starts_with(sv);

s.compare(s.size() - 6, 6, "suffix") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with("suffix");

s.compare(s.size() - 6, strlen("abcdef"), "suffix") == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with("suffix");

std::string suffix = "suffix";
s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with(suffix);

s.rfind("suffix") == s.size() - 6;
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with("suffix");

s.rfind("suffix") == s.size() - strlen("suffix");
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with("suffix");

s.rfind(suffix) == s.size() - suffix.size();
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with(suffix);

s.rfind(suffix, std::string::npos) == s.size() - suffix.size();
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with(suffix);

s.rfind(suffix) == (s.size() - suffix.size());
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with(suffix);

s.rfind(suffix, s.npos) == (s.size() - suffix.size());
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with(suffix);

s.rfind(suffix, s.npos) == (((s.size()) - (suffix.size())));
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with(suffix);

s.rfind(suffix) != s.size() - suffix.size();
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: !s.ends_with(suffix);

(s.size() - suffix.size()) == s.rfind(suffix);
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: s.ends_with(suffix);

struct S {
std::string s;
} t;
t.s.rfind(suffix) == (t.s.size() - suffix.size());
// CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use ends_with
// CHECK-FIXES: t.s.ends_with(suffix);

// Expressions that don't trigger the check are here.
#define EQ(x, y) ((x) == (y))
EQ(s.find("a"), 0);
Expand All @@ -219,4 +275,5 @@ void test(std::string s, std::string_view sv, sub_string ss, sub_sub_string sss,
STARTS_WITH_COMPARE(s, s) == 0;

s.compare(0, 1, "ab") == 0;
s.rfind(suffix, 1) == s.size() - suffix.size();
}
13 changes: 13 additions & 0 deletions clang/bindings/python/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ if(${LLVM_NATIVE_ARCH} MATCHES "^(AArch64|Hexagon|Sparc|SystemZ)$")
set(RUN_PYTHON_TESTS FALSE)
endif()

# Tests will fail if cross-compiling for a different target, as tests will try
# to use the host Python3_EXECUTABLE and make FFI calls to functions in target
# libraries.
if(CMAKE_CROSSCOMPILING)
# FIXME: Consider a solution that allows better control over these tests in
# a crosscompiling scenario. e.g. registering them with lit to allow them to
# be explicitly skipped via appropriate LIT_ARGS, or adding a mechanism to
# allow specifying a python interpreter compiled for the target that could
# be executed using qemu-user.
message(WARNING "check-clang-python not added to check-all as these tests fail in a cross-build setup")
set(RUN_PYTHON_TESTS FALSE)
endif()

if(RUN_PYTHON_TESTS)
set_property(GLOBAL APPEND PROPERTY
LLVM_ALL_ADDITIONAL_TEST_TARGETS check-clang-python)
Expand Down
50 changes: 37 additions & 13 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5406,22 +5406,46 @@ the configuration (without a prefix: ``Auto``).

.. _ReflowComments:

**ReflowComments** (``Boolean``) :versionbadge:`clang-format 3.8` :ref:`¶ <ReflowComments>`
If ``true``, clang-format will attempt to re-flow comments. That is it
will touch a comment and *reflow* long comments into new lines, trying to
obey the ``ColumnLimit``.
**ReflowComments** (``ReflowCommentsStyle``) :versionbadge:`clang-format 3.8` :ref:`¶ <ReflowComments>`
Comment reformatting style.

.. code-block:: c++
Possible values:

* ``RCS_Never`` (in configuration: ``Never``)
Leave comments untouched.

.. code-block:: c++

// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
* and a misaligned second line */
* ``RCS_IndentOnly`` (in configuration: ``IndentOnly``)
Only apply indentation rules, moving comments left or right, without
changing formatting inside the comments.

.. code-block:: c++

// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
* and a misaligned second line */
* ``RCS_Always`` (in configuration: ``Always``)
Apply indentation rules and reflow long comments into new lines, trying
to obey the ``ColumnLimit``.

.. code-block:: c++

// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
// information
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
* information */
/* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
* information and a misaligned second line */
false:
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */

true:
// veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
// information
/* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
* information */

.. _RemoveBracesLLVM:

Expand Down
17 changes: 12 additions & 5 deletions clang/docs/ClangPlugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,6 @@ The members of ``ParsedAttrInfo`` that a plugin attribute must define are:
attribute, each of which consists of an attribute syntax and how the
attribute name is spelled for that syntax. If the syntax allows a scope then
the spelling must be "scope::attr" if a scope is present or "::attr" if not.
* ``handleDeclAttribute``, which is the function that applies the attribute to
a declaration. It is responsible for checking that the attribute's arguments
are valid, and typically applies the attribute by adding an ``Attr`` to the
``Decl``. It returns either ``AttributeApplied``, to indicate that the
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.

The members of ``ParsedAttrInfo`` that may need to be defined, depending on the
attribute, are:
Expand All @@ -105,6 +100,18 @@ attribute, are:
arguments to the attribute.
* ``diagAppertainsToDecl``, which checks if the attribute has been used on the
right kind of declaration and issues a diagnostic if not.
* ``handleDeclAttribute``, which is the function that applies the attribute to
a declaration. It is responsible for checking that the attribute's arguments
are valid, and typically applies the attribute by adding an ``Attr`` to the
``Decl``. It returns either ``AttributeApplied``, to indicate that the
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.
* ``diagAppertainsToStmt``, which checks if the attribute has been used on the
right kind of statement and issues a diagnostic if not.
* ``handleStmtAttribute``, which is the function that applies the attribute to
a statement. It is responsible for checking that the attribute's arguments
are valid, and typically applies the attribute by adding an ``Attr`` to the
``Stmt``. It returns either ``AttributeApplied``, to indicate that the
attribute was successfully applied, or ``AttributeNotApplied`` if it wasn't.
* ``diagLangOpts``, which checks if the attribute is permitted for the current
language mode and issues a diagnostic if not.
* ``existsInTarget``, which checks if the attribute is permitted for the given
Expand Down
7 changes: 7 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,8 @@ Non-comprehensive list of changes in this release
- The floating point comparison builtins (``__builtin_isgreater``,
``__builtin_isgreaterequal``, ``__builtin_isless``, etc.) and
``__builtin_signbit`` can now be used in constant expressions.
- Plugins can now define custom attributes that apply to statements
as well as declarations.

New Compiler Flags
------------------
Expand Down Expand Up @@ -510,6 +512,7 @@ Bug Fixes to C++ Support
and undeclared templates. (#GH107047, #GH49093)
- Clang no longer crashes when a lambda contains an invalid block declaration that contains an unexpanded
parameter pack. (#GH109148)
- Fixed overload handling for object parameters with top-level cv-qualifiers in explicit member functions (#GH100394)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -630,6 +633,8 @@ WebAssembly Support
AVR Support
^^^^^^^^^^^

- Reject C/C++ compilation for avr1 devices which have no SRAM.

DWARF Support in Clang
----------------------

Expand Down Expand Up @@ -661,6 +666,8 @@ clang-format
- Adds ``BreakBinaryOperations`` option.
- Adds ``TemplateNames`` option.
- Adds ``AlignFunctionDeclarations`` option to ``AlignConsecutiveDeclarations``.
- Adds ``IndentOnly`` suboption to ``ReflowComments`` to fix the indentation of multi-line comments
without touching their contents, renames ``false`` to ``Never``, and ``true`` to ``Always``.

libclang
--------
Expand Down
48 changes: 48 additions & 0 deletions clang/examples/Attribute/Attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,54 @@ struct ExampleAttrInfo : public ParsedAttrInfo {
}
return AttributeApplied;
}

bool diagAppertainsToStmt(Sema &S, const ParsedAttr &Attr,
const Stmt *St) const override {
// This attribute appertains to for loop statements only.
if (!isa<ForStmt>(St)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str)
<< Attr << Attr.isRegularKeywordAttribute() << "for loop statements";
return false;
}
return true;
}

AttrHandling handleStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &Attr,
class Attr *&Result) const override {
// We make some rules here:
// 1. Only accept at most 3 arguments here.
// 2. The first argument must be a string literal if it exists.
if (Attr.getNumArgs() > 3) {
unsigned ID = S.getDiagnostics().getCustomDiagID(
DiagnosticsEngine::Error,
"'example' attribute only accepts at most three arguments");
S.Diag(Attr.getLoc(), ID);
return AttributeNotApplied;
}
// If there are arguments, the first argument should be a string literal.
if (Attr.getNumArgs() > 0) {
auto *Arg0 = Attr.getArgAsExpr(0);
StringLiteral *Literal =
dyn_cast<StringLiteral>(Arg0->IgnoreParenCasts());
if (!Literal) {
unsigned ID = S.getDiagnostics().getCustomDiagID(
DiagnosticsEngine::Error, "first argument to the 'example' "
"attribute must be a string literal");
S.Diag(Attr.getLoc(), ID);
return AttributeNotApplied;
}
SmallVector<Expr *, 16> ArgsBuf;
for (unsigned i = 0; i < Attr.getNumArgs(); i++) {
ArgsBuf.push_back(Attr.getArgAsExpr(i));
}
Result = AnnotateAttr::Create(S.Context, "example", ArgsBuf.data(),
ArgsBuf.size(), Attr.getRange());
} else {
Result = AnnotateAttr::Create(S.Context, "example", nullptr, 0,
Attr.getRange());
}
return AttributeApplied;
}
};

} // namespace
Expand Down
28 changes: 28 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ def FminF16F128 : Builtin, F16F128MathTemplate {
let Prototype = "T(T, T)";
}

def FmaximumNumF16F128 : Builtin, F16F128MathTemplate {
let Spellings = ["__builtin_fmaximum_num"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
let Prototype = "T(T, T)";
}

def FminimumNumF16F128 : Builtin, F16F128MathTemplate {
let Spellings = ["__builtin_fminimum_num"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr];
let Prototype = "T(T, T)";
}

def Atan2F128 : Builtin {
let Spellings = ["__builtin_atan2f128"];
let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions];
Expand Down Expand Up @@ -3728,6 +3740,22 @@ def Fmin : FPMathTemplate, LibBuiltin<"math.h"> {
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}

def FmaximumNum : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fmaximum_num"];
let Attributes = [NoThrow, Const];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}

def FminimumNum : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["fminimum_num"];
let Attributes = [NoThrow, Const];
let Prototype = "T(T, T)";
let AddBuiltinPrefixedAlias = 1;
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
}

def Hypot : FPMathTemplate, LibBuiltin<"math.h"> {
let Spellings = ["hypot"];
let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions];
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ inline StreamTy &printOpenACCGangKind(StreamTy &Out, OpenACCGangKind GK) {
case OpenACCGangKind::Static:
return Out << "static";
}
llvm_unreachable("unknown gang kind");
}
inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
OpenACCGangKind Op) {
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Basic/ParsedAttrInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

namespace clang {

class Attr;
class Decl;
class LangOptions;
class ParsedAttr;
Expand Down Expand Up @@ -154,6 +155,15 @@ struct ParsedAttrInfo {
const ParsedAttr &Attr) const {
return NotHandled;
}
/// If this ParsedAttrInfo knows how to handle this ParsedAttr applied to this
/// Stmt then do so (referencing the resulting Attr in Result) and return
/// either AttributeApplied if it was applied or AttributeNotApplied if it
/// wasn't. Otherwise return NotHandled.
virtual AttrHandling handleStmtAttribute(Sema &S, Stmt *St,
const ParsedAttr &Attr,
class Attr *&Result) const {
return NotHandled;
}

static const ParsedAttrInfo &get(const AttributeCommonInfo &A);
static ArrayRef<const ParsedAttrInfo *> getAllBuiltin();
Expand Down
51 changes: 35 additions & 16 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3847,24 +3847,43 @@ struct FormatStyle {
ReferenceAlignmentStyle ReferenceAlignment;

// clang-format off
/// If ``true``, clang-format will attempt to re-flow comments. That is it
/// will touch a comment and *reflow* long comments into new lines, trying to
/// obey the ``ColumnLimit``.
/// \code
/// false:
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
///
/// true:
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
/// // information
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
/// * information */
/// \endcode
/// \version 3.8
bool ReflowComments;
/// \brief Types of comment reflow style.
enum ReflowCommentsStyle : int8_t {
/// Leave comments untouched.
/// \code
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/// * and a misaligned second line */
/// \endcode
RCS_Never,
/// Only apply indentation rules, moving comments left or right, without
/// changing formatting inside the comments.
/// \code
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information */
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of information
/// * and a misaligned second line */
/// \endcode
RCS_IndentOnly,
/// Apply indentation rules and reflow long comments into new lines, trying
/// to obey the ``ColumnLimit``.
/// \code
/// // veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
/// // information
/// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
/// * information */
/// /* third veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of
/// * information and a misaligned second line */
/// \endcode
RCS_Always
};
// clang-format on

/// \brief Comment reformatting style.
/// \version 3.8
ReflowCommentsStyle ReflowComments;

/// Remove optional braces of control statements (``if``, ``else``, ``for``,
/// and ``while``) in C++ according to the LLVM coding style.
/// \warning
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -872,8 +872,6 @@ class Sema final : public SemaBase {
/// For example, user-defined classes, built-in "id" type, etc.
Scope *TUScope;

bool WarnedStackExhausted = false;

void incrementMSManglingNumber() const {
return CurScope->incrementMSManglingNumber();
}
Expand Down Expand Up @@ -1185,6 +1183,8 @@ class Sema final : public SemaBase {
std::optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
bool WarnedDarwinSDKInfoMissing = false;

bool WarnedStackExhausted = false;

Sema(const Sema &) = delete;
void operator=(const Sema &) = delete;

Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3416,6 +3416,9 @@ bool Compiler<Emitter>::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {

template <class Emitter>
bool Compiler<Emitter>::VisitBlockExpr(const BlockExpr *E) {
if (DiscardResult)
return true;

const Function *Func = nullptr;
if (auto F = Compiler<ByteCodeEmitter>(Ctx, P).compileObjCBlock(E))
Func = F;
Expand Down
26 changes: 26 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15310,6 +15310,32 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result = RHS;
return true;
}

case Builtin::BI__builtin_fmaximum_num:
case Builtin::BI__builtin_fmaximum_numf:
case Builtin::BI__builtin_fmaximum_numl:
case Builtin::BI__builtin_fmaximum_numf16:
case Builtin::BI__builtin_fmaximum_numf128: {
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluateFloat(E->getArg(1), RHS, Info))
return false;
Result = maximumnum(Result, RHS);
return true;
}

case Builtin::BI__builtin_fminimum_num:
case Builtin::BI__builtin_fminimum_numf:
case Builtin::BI__builtin_fminimum_numl:
case Builtin::BI__builtin_fminimum_numf16:
case Builtin::BI__builtin_fminimum_numf128: {
APFloat RHS(0.);
if (!EvaluateFloat(E->getArg(0), Result, Info) ||
!EvaluateFloat(E->getArg(1), RHS, Info))
return false;
Result = minimumnum(Result, RHS);
return true;
}
}
}

Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/InheritViz.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,11 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
QualType CanonType = Context.getCanonicalType(Type);

if (FromVirtual) {
if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end())
if (!KnownVirtualBases.insert(CanonType).second)
return;

// We haven't seen this virtual base before, so display it and
// its bases.
KnownVirtualBases.insert(CanonType);
}

// Declare the node itself.
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Basic/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,9 @@ ARMTargetInfo::ARMTargetInfo(const llvm::Triple &Triple,
switch (Triple.getEnvironment()) {
case llvm::Triple::Android:
case llvm::Triple::GNUEABI:
case llvm::Triple::GNUEABIT64:
case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABIHFT64:
case llvm::Triple::MuslEABI:
case llvm::Triple::MuslEABIHF:
case llvm::Triple::OpenHOS:
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/OSTargets.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,10 @@ class LLVM_LIBRARY_VISIBILITY LinuxTargetInfo : public OSTargetInfo<Target> {
Builder.defineMacro("_GNU_SOURCE");
if (this->HasFloat128)
Builder.defineMacro("__FLOAT128__");
if (Triple.isTime64ABI()) {
Builder.defineMacro("_FILE_OFFSET_BITS", "64");
Builder.defineMacro("_TIME_BITS", "64");
}
}

public:
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ bool RISCVTargetInfo::validateAsmConstraint(
return true;
case 'v':
// A vector register.
if (Name[1] == 'r' || Name[1] == 'm') {
if (Name[1] == 'r' || Name[1] == 'd' || Name[1] == 'm') {
Info.setAllowsRegister();
Name += 1;
return true;
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2869,6 +2869,28 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Intrinsic::minnum,
Intrinsic::experimental_constrained_minnum));

case Builtin::BIfmaximum_num:
case Builtin::BIfmaximum_numf:
case Builtin::BIfmaximum_numl:
case Builtin::BI__builtin_fmaximum_num:
case Builtin::BI__builtin_fmaximum_numf:
case Builtin::BI__builtin_fmaximum_numf16:
case Builtin::BI__builtin_fmaximum_numl:
case Builtin::BI__builtin_fmaximum_numf128:
return RValue::get(
emitBuiltinWithOneOverloadedType<2>(*this, E, Intrinsic::maximumnum));

case Builtin::BIfminimum_num:
case Builtin::BIfminimum_numf:
case Builtin::BIfminimum_numl:
case Builtin::BI__builtin_fminimum_num:
case Builtin::BI__builtin_fminimum_numf:
case Builtin::BI__builtin_fminimum_numf16:
case Builtin::BI__builtin_fminimum_numl:
case Builtin::BI__builtin_fminimum_numf128:
return RValue::get(
emitBuiltinWithOneOverloadedType<2>(*this, E, Intrinsic::minimumnum));

// fmod() is a special-case. It maps to the frem instruction rather than an
// LLVM intrinsic.
case Builtin::BIfmod:
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1528,7 +1528,12 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) {
///
LValue CodeGenFunction::EmitLValue(const Expr *E,
KnownNonNull_t IsKnownNonNull) {
LValue LV = EmitLValueHelper(E, IsKnownNonNull);
// Running with sufficient stack space to avoid deeply nested expressions
// cause a stack overflow.
LValue LV;
CGM.runWithSufficientStackSpace(
E->getExprLoc(), [&] { LV = EmitLValueHelper(E, IsKnownNonNull); });

if (IsKnownNonNull && !LV.isKnownNonNull())
LV.setKnownNonNull();
return LV;
Expand Down
45 changes: 14 additions & 31 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1713,25 +1713,15 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition(
if (!Ctor && !Dtor)
return nullptr;

llvm::Type *CopyCtorTyArgs[] = {CGM.VoidPtrTy, CGM.VoidPtrTy};
auto *CopyCtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CopyCtorTyArgs,
/*isVarArg=*/false)
->getPointerTo();
// Copying constructor for the threadprivate variable.
// Must be NULL - reserved by runtime, but currently it requires that this
// parameter is always NULL. Otherwise it fires assertion.
CopyCtor = llvm::Constant::getNullValue(CopyCtorTy);
CopyCtor = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
if (Ctor == nullptr) {
auto *CtorTy = llvm::FunctionType::get(CGM.VoidPtrTy, CGM.VoidPtrTy,
/*isVarArg=*/false)
->getPointerTo();
Ctor = llvm::Constant::getNullValue(CtorTy);
Ctor = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
}
if (Dtor == nullptr) {
auto *DtorTy = llvm::FunctionType::get(CGM.VoidTy, CGM.VoidPtrTy,
/*isVarArg=*/false)
->getPointerTo();
Dtor = llvm::Constant::getNullValue(DtorTy);
Dtor = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
}
if (!CGF) {
auto *InitFunctionTy =
Expand Down Expand Up @@ -1817,7 +1807,7 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF,
OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_threadprivate_cached),
Args),
VarLVType->getPointerTo(/*AddrSpace=*/0)),
CGF.Builder.getPtrTy(0)),
VarLVType, CGM.getContext().getTypeAlignInChars(VarType));
}

Expand Down Expand Up @@ -2131,10 +2121,7 @@ static Address emitAddrOfVarFromArray(CodeGenFunction &CGF, Address Array,
llvm::Value *Ptr = CGF.Builder.CreateLoad(PtrAddr);

llvm::Type *ElemTy = CGF.ConvertTypeForMem(Var->getType());
return Address(
CGF.Builder.CreateBitCast(
Ptr, ElemTy->getPointerTo(Ptr->getType()->getPointerAddressSpace())),
ElemTy, CGF.getContext().getDeclAlign(Var));
return Address(Ptr, ElemTy, CGF.getContext().getDeclAlign(Var));
}

static llvm::Value *emitCopyprivateCopyFunction(
Expand Down Expand Up @@ -2166,11 +2153,11 @@ static llvm::Value *emitCopyprivateCopyFunction(
// Src = (void*[n])(RHSArg);
Address LHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&LHSArg)),
ArgsElemType->getPointerTo()),
CGF.Builder.getPtrTy(0)),
ArgsElemType, CGF.getPointerAlign());
Address RHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&RHSArg)),
ArgsElemType->getPointerTo()),
CGF.Builder.getPtrTy(0)),
ArgsElemType, CGF.getPointerAlign());
// *(Type0*)Dst[0] = *(Type0*)Src[0];
// *(Type1*)Dst[1] = *(Type1*)Src[1];
Expand Down Expand Up @@ -3681,9 +3668,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc,
QualType KmpTaskTWithPrivatesQTy = C.getRecordType(KmpTaskTWithPrivatesQTyRD);
QualType KmpTaskTWithPrivatesPtrQTy =
C.getPointerType(KmpTaskTWithPrivatesQTy);
llvm::Type *KmpTaskTWithPrivatesTy = CGF.ConvertType(KmpTaskTWithPrivatesQTy);
llvm::Type *KmpTaskTWithPrivatesPtrTy =
KmpTaskTWithPrivatesTy->getPointerTo();
llvm::Type *KmpTaskTWithPrivatesPtrTy = CGF.Builder.getPtrTy(0);
llvm::Value *KmpTaskTWithPrivatesTySize =
CGF.getTypeSize(KmpTaskTWithPrivatesQTy);
QualType SharedsPtrTy = C.getPointerType(SharedsTy);
Expand Down Expand Up @@ -4399,7 +4384,7 @@ Address CGOpenMPRuntime::emitDepobjDependClause(
Args, ".dep.arr.addr");
llvm::Type *KmpDependInfoLlvmTy = CGF.ConvertTypeForMem(KmpDependInfoTy);
Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
Addr, KmpDependInfoLlvmTy->getPointerTo());
Addr, CGF.Builder.getPtrTy(0));
DependenciesArray = Address(Addr, KmpDependInfoLlvmTy, Align);
// Write number of elements in the first element of array for depobj.
LValue Base = CGF.MakeAddrLValue(DependenciesArray, KmpDependInfoTy);
Expand Down Expand Up @@ -4841,11 +4826,11 @@ llvm::Function *CGOpenMPRuntime::emitReductionFunction(
// Src = (void*[n])(RHSArg);
Address LHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&LHSArg)),
ArgsElemType->getPointerTo()),
CGF.Builder.getPtrTy(0)),
ArgsElemType, CGF.getPointerAlign());
Address RHS(CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(&RHSArg)),
ArgsElemType->getPointerTo()),
CGF.Builder.getPtrTy(0)),
ArgsElemType, CGF.getPointerAlign());

// ...
Expand Down Expand Up @@ -5277,8 +5262,7 @@ static llvm::Value *emitReduceInitFunction(CodeGenModule &CGM,
CGF.StartFunction(GlobalDecl(), C.VoidTy, Fn, FnInfo, Args, Loc, Loc);
QualType PrivateType = RCG.getPrivateType(N);
Address PrivateAddr = CGF.EmitLoadOfPointer(
CGF.GetAddrOfLocalVar(&Param).withElementType(
CGF.ConvertTypeForMem(PrivateType)->getPointerTo()),
CGF.GetAddrOfLocalVar(&Param).withElementType(CGF.Builder.getPtrTy(0)),
C.getPointerType(PrivateType)->castAs<PointerType>());
llvm::Value *Size = nullptr;
// If the size of the reduction item is non-constant, load it from global
Expand Down Expand Up @@ -5366,15 +5350,14 @@ static llvm::Value *emitReduceCombFunction(CodeGenModule &CGM,
// Pull out the pointer to the variable.
CGF.EmitLoadOfPointer(
CGF.GetAddrOfLocalVar(&ParamInOut)
.withElementType(
CGF.ConvertTypeForMem(LHSVD->getType())->getPointerTo()),
.withElementType(CGF.Builder.getPtrTy(0)),
C.getPointerType(LHSVD->getType())->castAs<PointerType>()));
PrivateScope.addPrivate(
RHSVD,
// Pull out the pointer to the variable.
CGF.EmitLoadOfPointer(
CGF.GetAddrOfLocalVar(&ParamIn).withElementType(
CGF.ConvertTypeForMem(RHSVD->getType())->getPointerTo()),
CGF.Builder.getPtrTy(0)),
C.getPointerType(RHSVD->getType())->castAs<PointerType>()));
PrivateScope.Privatize();
// Emit the combiner body:
Expand Down
19 changes: 15 additions & 4 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/CodeGen/BackendUtil.h"
Expand Down Expand Up @@ -175,10 +176,7 @@ createTargetCodeGenInfo(CodeGenModule &CGM) {
else if (ABIStr == "aapcs16")
Kind = ARMABIKind::AAPCS16_VFP;
else if (CodeGenOpts.FloatABI == "hard" ||
(CodeGenOpts.FloatABI != "soft" &&
(Triple.getEnvironment() == llvm::Triple::GNUEABIHF ||
Triple.getEnvironment() == llvm::Triple::MuslEABIHF ||
Triple.getEnvironment() == llvm::Triple::EABIHF)))
(CodeGenOpts.FloatABI != "soft" && Triple.isHardFloatABI()))
Kind = ARMABIKind::AAPCS_VFP;

return createARMTargetCodeGenInfo(CGM, Kind);
Expand Down Expand Up @@ -1596,6 +1594,19 @@ void CodeGenModule::ErrorUnsupported(const Decl *D, const char *Type) {
getDiags().Report(Context.getFullLoc(D->getLocation()), DiagID) << Msg;
}

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

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

llvm::ConstantInt *CodeGenModule::getSize(CharUnits size) {
return llvm::ConstantInt::get(SizeTy, size.getQuantity());
}
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ class CodeGenModule : public CodeGenTypeCache {
std::unique_ptr<llvm::IndexedInstrProfReader> PGOReader;
InstrProfStats PGOStats;
std::unique_ptr<llvm::SanitizerStatReport> SanStats;
bool WarnedStackExhausted = false;

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

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

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

/// Set the attributes on the LLVM function for the given decl and function
/// info. This applies attributes necessary for handling the ABI as well as
/// user specified attributes like section.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/Targets/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ class ARMABIInfo : public ABIInfo {
case llvm::Triple::EABI:
case llvm::Triple::EABIHF:
case llvm::Triple::GNUEABI:
case llvm::Triple::GNUEABIT64:
case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABIHFT64:
case llvm::Triple::MuslEABI:
case llvm::Triple::MuslEABIHF:
return true;
Expand All @@ -48,6 +50,7 @@ class ARMABIInfo : public ABIInfo {
switch (getTarget().getTriple().getEnvironment()) {
case llvm::Triple::EABIHF:
case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABIHFT64:
case llvm::Triple::MuslEABIHF:
return true;
default:
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,8 @@ static llvm::Triple computeTargetTriple(const Driver &D,
if (A->getOption().matches(options::OPT_m64) ||
A->getOption().matches(options::OPT_maix64)) {
AT = Target.get64BitArchVariant().getArch();
if (Target.getEnvironment() == llvm::Triple::GNUX32)
if (Target.getEnvironment() == llvm::Triple::GNUX32 ||
Target.getEnvironment() == llvm::Triple::GNUT64)
Target.setEnvironment(llvm::Triple::GNU);
else if (Target.getEnvironment() == llvm::Triple::MuslX32)
Target.setEnvironment(llvm::Triple::Musl);
Expand Down Expand Up @@ -673,6 +674,7 @@ static llvm::Triple computeTargetTriple(const Driver &D,
} else if (ABIName == "n32") {
Target = Target.get64BitArchVariant();
if (Target.getEnvironment() == llvm::Triple::GNU ||
Target.getEnvironment() == llvm::Triple::GNUT64 ||
Target.getEnvironment() == llvm::Triple::GNUABI64)
Target.setEnvironment(llvm::Triple::GNUABIN32);
else if (Target.getEnvironment() == llvm::Triple::Musl ||
Expand All @@ -681,6 +683,7 @@ static llvm::Triple computeTargetTriple(const Driver &D,
} else if (ABIName == "64") {
Target = Target.get64BitArchVariant();
if (Target.getEnvironment() == llvm::Triple::GNU ||
Target.getEnvironment() == llvm::Triple::GNUT64 ||
Target.getEnvironment() == llvm::Triple::GNUABIN32)
Target.setEnvironment(llvm::Triple::GNUABI64);
else if (Target.getEnvironment() == llvm::Triple::Musl ||
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Driver/ToolChains/AVR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,14 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
void AVRToolChain::addClangTargetOptions(
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
Action::OffloadKind DeviceOffloadKind) const {
// Reject C/C++ compilation for avr1 devices since they have no SRAM.
const Driver &D = getDriver();
std::string CPU = getCPUName(D, DriverArgs, getTriple());
std::optional<StringRef> FamilyName = GetMCUFamilyName(CPU);
if (CPU == "avr1" || (FamilyName && *FamilyName == "avr1"))
D.Diag(diag::err_drv_opt_unsupported_input_type)
<< "-mmcu=" + CPU << "c/c++";

// By default, use `.ctors` (not `.init_array`), as required by libgcc, which
// runs constructors/destructors on AVR.
if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ void arm::setFloatABIInTriple(const Driver &D, const ArgList &Args,
Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHF
: llvm::Triple::GNUEABI);
break;
case llvm::Triple::GNUEABIT64:
case llvm::Triple::GNUEABIHFT64:
Triple.setEnvironment(isHardFloat ? llvm::Triple::GNUEABIHFT64
: llvm::Triple::GNUEABIT64);
break;
case llvm::Triple::EABI:
case llvm::Triple::EABIHF:
Triple.setEnvironment(isHardFloat ? llvm::Triple::EABIHF
Expand Down Expand Up @@ -414,10 +419,12 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) {
return FloatABI::Soft;
switch (Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABIHFT64:
case llvm::Triple::MuslEABIHF:
case llvm::Triple::EABIHF:
return FloatABI::Hard;
case llvm::Triple::GNUEABI:
case llvm::Triple::GNUEABIT64:
case llvm::Triple::MuslEABI:
case llvm::Triple::EABI:
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2698,6 +2698,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
case llvm::Triple::thumb:
LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHFT64 ||
TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::EABIHF) {
TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples));
Expand All @@ -2709,6 +2710,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
case llvm::Triple::thumbeb:
LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs));
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHFT64 ||
TargetTriple.getEnvironment() == llvm::Triple::MuslEABIHF ||
TargetTriple.getEnvironment() == llvm::Triple::EABIHF) {
TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples));
Expand Down
20 changes: 10 additions & 10 deletions clang/lib/Driver/ToolChains/HIPUtility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,20 +340,19 @@ void HIP::constructHIPFatbinCommand(Compilation &C, const JobAction &JA,
void HIP::constructGenerateObjFileFromHIPFatBinary(
Compilation &C, const InputInfo &Output, const InputInfoList &Inputs,
const ArgList &Args, const JobAction &JA, const Tool &T) {
const ToolChain &TC = T.getToolChain();
std::string Name = std::string(llvm::sys::path::stem(Output.getFilename()));

// Create Temp Object File Generator,
// Offload Bundled file and Bundled Object file.
// Keep them if save-temps is enabled.
const char *McinFile;
const char *ObjinFile;
const char *BundleFile;
if (C.getDriver().isSaveTempsEnabled()) {
McinFile = C.getArgs().MakeArgString(Name + ".mcin");
ObjinFile = C.getArgs().MakeArgString(Name + ".mcin");
BundleFile = C.getArgs().MakeArgString(Name + ".hipfb");
} else {
auto TmpNameMcin = C.getDriver().GetTemporaryPath(Name, "mcin");
McinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin));
ObjinFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameMcin));
auto TmpNameFb = C.getDriver().GetTemporaryPath(Name, "hipfb");
BundleFile = C.addTempFile(C.getArgs().MakeArgString(TmpNameFb));
}
Expand Down Expand Up @@ -454,7 +453,7 @@ void HIP::constructGenerateObjFileFromHIPFatBinary(

// Open script file and write the contents.
std::error_code EC;
llvm::raw_fd_ostream Objf(McinFile, EC, llvm::sys::fs::OF_None);
llvm::raw_fd_ostream Objf(ObjinFile, EC, llvm::sys::fs::OF_None);

if (EC) {
C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
Expand All @@ -463,10 +462,11 @@ void HIP::constructGenerateObjFileFromHIPFatBinary(

Objf << ObjBuffer;

ArgStringList McArgs{"-triple", Args.MakeArgString(HostTriple.normalize()),
ArgStringList McArgs{"-target", Args.MakeArgString(HostTriple.normalize()),
"-o", Output.getFilename(),
McinFile, "--filetype=obj"};
const char *Mc = Args.MakeArgString(TC.GetProgramPath("llvm-mc"));
C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(), Mc,
McArgs, Inputs, Output));
"-x", "assembler",
ObjinFile, "-c"};
const char *Clang = Args.MakeArgString(C.getDriver().ClangExecutable);
C.addCommand(std::make_unique<Command>(JA, T, ResponseFileSupport::None(),
Clang, McArgs, Inputs, Output));
}
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const {
case llvm::Triple::thumbeb: {
const bool HF =
Triple.getEnvironment() == llvm::Triple::GNUEABIHF ||
Triple.getEnvironment() == llvm::Triple::GNUEABIHFT64 ||
tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard;

LibDir = "lib";
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Format/BreakableToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset,
unsigned ColumnLimit, unsigned ContentStartColumn,
const llvm::Regex &CommentPragmasRegex) const {
// Don't break lines matching the comment pragmas regex.
if (CommentPragmasRegex.match(Content[LineIndex]))
if (!AlwaysReflow || CommentPragmasRegex.match(Content[LineIndex]))
return Split(StringRef::npos, 0);
return getCommentSplit(Content[LineIndex].substr(TailOffset),
ContentStartColumn, ColumnLimit, Style.TabWidth,
Expand Down Expand Up @@ -608,7 +608,7 @@ BreakableToken::Split BreakableBlockComment::getSplit(
unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit,
unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const {
// Don't break lines matching the comment pragmas regex.
if (CommentPragmasRegex.match(Content[LineIndex]))
if (!AlwaysReflow || CommentPragmasRegex.match(Content[LineIndex]))
return Split(StringRef::npos, 0);
return getCommentSplit(Content[LineIndex].substr(TailOffset),
ContentStartColumn, ColumnLimit, Style.TabWidth,
Expand Down Expand Up @@ -855,7 +855,8 @@ bool BreakableBlockComment::mayReflow(
StringRef IndentContent = Content[LineIndex];
if (Lines[LineIndex].ltrim(Blanks).starts_with("*"))
IndentContent = Lines[LineIndex].ltrim(Blanks).substr(1);
return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
return LineIndex > 0 && AlwaysReflow &&
!CommentPragmasRegex.match(IndentContent) &&
mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
!switchesFormatting(tokenAt(LineIndex));
}
Expand Down Expand Up @@ -1160,7 +1161,8 @@ bool BreakableLineCommentSection::mayReflow(
// // text that protrudes
// // into text with different indent
// We do reflow in that case in block comments.
return LineIndex > 0 && !CommentPragmasRegex.match(IndentContent) &&
return LineIndex > 0 && AlwaysReflow &&
!CommentPragmasRegex.match(IndentContent) &&
mayReflowContent(Content[LineIndex]) && !Tok.Finalized &&
!switchesFormatting(tokenAt(LineIndex)) &&
OriginalPrefix[LineIndex] == OriginalPrefix[LineIndex - 1];
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Format/BreakableToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ class BreakableComment : public BreakableToken {
// The intended start column of the first line of text from this section.
unsigned StartColumn;

const bool AlwaysReflow = Style.ReflowComments == FormatStyle::RCS_Always;

// The prefix to use in front a line that has been reflown up.
// For example, when reflowing the second line after the first here:
// // comment 1
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2471,7 +2471,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
State.Line->InPPDirective, Encoding, Style);
}
} else if (Current.is(TT_BlockComment)) {
if (!Style.ReflowComments ||
if (Style.ReflowComments == FormatStyle::RCS_Never ||
// If a comment token switches formatting, like
// /* clang-format on */, we don't want to break it further,
// but we may still want to adjust its indentation.
Expand All @@ -2492,7 +2492,7 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current,
}
return true;
}();
if (!Style.ReflowComments ||
if (Style.ReflowComments == FormatStyle::RCS_Never ||
CommentPragmasRegex.match(Current.TokenText.substr(2)) ||
switchesFormatting(Current) || !RegularComments) {
return nullptr;
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,17 @@ template <> struct MappingTraits<FormatStyle::RawStringFormat> {
}
};

template <> struct ScalarEnumerationTraits<FormatStyle::ReflowCommentsStyle> {
static void enumeration(IO &IO, FormatStyle::ReflowCommentsStyle &Value) {
IO.enumCase(Value, "Never", FormatStyle::RCS_Never);
IO.enumCase(Value, "IndentOnly", FormatStyle::RCS_IndentOnly);
IO.enumCase(Value, "Always", FormatStyle::RCS_Always);
// For backward compatibility:
IO.enumCase(Value, "false", FormatStyle::RCS_Never);
IO.enumCase(Value, "true", FormatStyle::RCS_Always);
}
};

template <>
struct ScalarEnumerationTraits<FormatStyle::ReferenceAlignmentStyle> {
static void enumeration(IO &IO, FormatStyle::ReferenceAlignmentStyle &Value) {
Expand Down Expand Up @@ -1569,7 +1580,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.PPIndentWidth = -1;
LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
LLVMStyle.ReflowComments = true;
LLVMStyle.ReflowComments = FormatStyle::RCS_Always;
LLVMStyle.RemoveBracesLLVM = false;
LLVMStyle.RemoveParentheses = FormatStyle::RPS_Leave;
LLVMStyle.RemoveSemicolon = false;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1551,7 +1551,8 @@ class AnnotatingParser {
// Case D.
if (Keywords.isVerilogIdentifier(*Prev) && PrevPrev->is(tok::comma)) {
const FormatToken *PrevParen = PrevPrev->getPreviousNonComment();
if (PrevParen->is(tok::r_paren) && PrevParen->MatchingParen &&
if (PrevParen && PrevParen->is(tok::r_paren) &&
PrevParen->MatchingParen &&
PrevParen->MatchingParen->is(TT_VerilogInstancePortLParen)) {
return true;
}
Expand Down
10 changes: 5 additions & 5 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4623,9 +4623,9 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) {
// section on \p Line.
static bool
continuesLineCommentSection(const FormatToken &FormatTok,
const UnwrappedLine &Line,
const UnwrappedLine &Line, const FormatStyle &Style,
const llvm::Regex &CommentPragmasRegex) {
if (Line.Tokens.empty())
if (Line.Tokens.empty() || Style.ReflowComments != FormatStyle::RCS_Always)
return false;

StringRef IndentContent = FormatTok.TokenText;
Expand Down Expand Up @@ -4738,7 +4738,7 @@ void UnwrappedLineParser::flushComments(bool NewlineBeforeNext) {
// FIXME: Consider putting separate line comment sections as children to the
// unwrapped line instead.
Tok->ContinuesLineCommentSection =
continuesLineCommentSection(*Tok, *Line, CommentPragmasRegex);
continuesLineCommentSection(*Tok, *Line, Style, CommentPragmasRegex);
if (isOnNewLine(*Tok) && JustComments && !Tok->ContinuesLineCommentSection)
addUnwrappedLine();
pushToken(Tok);
Expand Down Expand Up @@ -4811,8 +4811,8 @@ void UnwrappedLineParser::distributeComments(
if (HasTrailAlignedWithNextToken && i == StartOfTrailAlignedWithNextToken) {
FormatTok->ContinuesLineCommentSection = false;
} else {
FormatTok->ContinuesLineCommentSection =
continuesLineCommentSection(*FormatTok, *Line, CommentPragmasRegex);
FormatTok->ContinuesLineCommentSection = continuesLineCommentSection(
*FormatTok, *Line, Style, CommentPragmasRegex);
}
if (!FormatTok->ContinuesLineCommentSection &&
(isOnNewLine(*FormatTok) || FormatTok->IsFirst)) {
Expand Down
8 changes: 3 additions & 5 deletions clang/lib/Sema/SemaAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,12 +750,10 @@ bool Sema::UnifySection(StringRef SectionName, int SectionFlags,
if (auto A = Decl->getAttr<SectionAttr>())
if (A->isImplicit())
PragmaLocation = A->getLocation();
auto SectionIt = Context.SectionInfos.find(SectionName);
if (SectionIt == Context.SectionInfos.end()) {
Context.SectionInfos[SectionName] =
ASTContext::SectionInfo(Decl, PragmaLocation, SectionFlags);
auto [SectionIt, Inserted] = Context.SectionInfos.try_emplace(
SectionName, Decl, PragmaLocation, SectionFlags);
if (Inserted)
return false;
}
// A pre-declared section takes precedence w/o diagnostic.
const auto &Section = SectionIt->second;
if (Section.SectionFlags == SectionFlags ||
Expand Down
23 changes: 18 additions & 5 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1422,8 +1422,12 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
// the implicit object parameter are of the same type.

auto NormalizeQualifiers = [&](const CXXMethodDecl *M, Qualifiers Q) {
if (M->isExplicitObjectMemberFunction())
if (M->isExplicitObjectMemberFunction()) {
auto ThisType = M->getFunctionObjectParameterReferenceType();
if (ThisType.isConstQualified())
Q.removeConst();
return Q;
}

// We do not allow overloading based off of '__restrict'.
Q.removeRestrict();
Expand All @@ -1439,14 +1443,23 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New,
return Q;
};

auto CompareType = [&](QualType Base, QualType D) {
auto BS = Base.getNonReferenceType().getCanonicalType().split();
auto AreQualifiersEqual = [&](SplitQualType BS, SplitQualType DS) {
BS.Quals = NormalizeQualifiers(OldMethod, BS.Quals);
DS.Quals = NormalizeQualifiers(NewMethod, DS.Quals);

if (OldMethod->isExplicitObjectMemberFunction()) {
BS.Quals.removeVolatile();
DS.Quals.removeVolatile();
}

return BS.Quals == DS.Quals;
};

auto CompareType = [&](QualType Base, QualType D) {
auto BS = Base.getNonReferenceType().getCanonicalType().split();
auto DS = D.getNonReferenceType().getCanonicalType().split();
DS.Quals = NormalizeQualifiers(NewMethod, DS.Quals);

if (BS.Quals != DS.Quals)
if (!AreQualifiersEqual(BS, DS))
return false;

if (OldMethod->isImplicitObjectMemberFunction() &&
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,10 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
case ParsedAttr::AT_Annotate:
return S.CreateAnnotationAttr(A);
default:
if (Attr *AT = nullptr; A.getInfo().handleStmtAttribute(S, St, A, AT) !=
ParsedAttrInfo::NotHandled) {
return AT;
}
// N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a
// declaration attribute is not written on a statement, but this code is
// needed for attributes in Attr.td that do not list any subjects.
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4057,11 +4057,10 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
// keep track of these diagnostics. They'll be emitted if this specialization
// is actually used.
if (Info.diag_begin() != Info.diag_end()) {
SuppressedDiagnosticsMap::iterator
Pos = SuppressedDiagnostics.find(Specialization->getCanonicalDecl());
if (Pos == SuppressedDiagnostics.end())
SuppressedDiagnostics[Specialization->getCanonicalDecl()]
.append(Info.diag_begin(), Info.diag_end());
auto [Pos, Inserted] =
SuppressedDiagnostics.try_emplace(Specialization->getCanonicalDecl());
if (Inserted)
Pos->second.append(Info.diag_begin(), Info.diag_end());
}

return TemplateDeductionResult::Success;
Expand Down
1 change: 1 addition & 0 deletions clang/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ if( NOT CLANG_BUILT_STANDALONE )
llvm-dwarfdump
llvm-ifs
llvm-lto2
llvm-mc
llvm-modextract
llvm-nm
llvm-objcopy
Expand Down
8 changes: 8 additions & 0 deletions clang/test/CodeGen/RISCV/riscv-inline-asm-rvv.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ vint32m1_t test_vr(vint32m1_t a, vint32m1_t b) {
return ret;
}

vint32m1_t test_vd(vint32m1_t a, vint32m1_t b) {
// CHECK-LABEL: define{{.*}} @test_vd
// CHECK: %0 = tail call <vscale x 2 x i32> asm sideeffect "vadd.vv $0, $1, $2", "=^vd,^vd,^vd"(<vscale x 2 x i32> %a, <vscale x 2 x i32> %b)
vint32m1_t ret;
asm volatile ("vadd.vv %0, %1, %2" : "=vd"(ret) : "vd"(a), "vd"(b));
return ret;
}

vbool1_t test_vm(vbool1_t a, vbool1_t b) {
// CHECK-LABEL: define{{.*}} @test_vm
// CHECK: %0 = tail call <vscale x 64 x i1> asm sideeffect "vmand.mm $0, $1, $2", "=^vm,^vm,^vm"(<vscale x 64 x i1> %a, <vscale x 64 x i1> %b)
Expand Down
61 changes: 60 additions & 1 deletion clang/test/CodeGen/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ int main(void) {
P(issignaling, (1.));
P(isfpclass, (1., 1));

Q(fmaximum_num, (1.0, 2.0));
Q(fmaximum_numf, (1.0, 2.0));
Q(fmaximum_numl, (1.0, 2.0));
Q(fminimum_num, (1.0, 2.0));
Q(fminimum_numf, (1.0, 2.0));
Q(fminimum_numl, (1.0, 2.0));

// Bitwise & Numeric Functions

P(abs, (N));
Expand Down Expand Up @@ -305,7 +312,7 @@ void test_float_builtins(__fp16 *H, float F, double D, long double LD) {
}

// CHECK-LABEL: define{{.*}} void @test_float_builtin_ops
void test_float_builtin_ops(float F, double D, long double LD) {
void test_float_builtin_ops(float F, double D, long double LD, int I) {
volatile float resf;
volatile double resd;
volatile long double resld;
Expand Down Expand Up @@ -353,6 +360,58 @@ void test_float_builtin_ops(float F, double D, long double LD) {
resld = __builtin_fmaxl(LD, LD);
// CHECK: call x86_fp80 @llvm.maxnum.f80

resf = __builtin_fminimum_numf(F, F);
// CHECK: call float @llvm.minimumnum.f32

resf = __builtin_fminimum_numf(I, I);
// CHECK: sitofp i32 {{%[0-9]+}} to float
// CHECK: sitofp i32 {{%[0-9]+}} to float
// CHECK: call float @llvm.minimumnum.f32

resf = __builtin_fminimum_numf(1.0, 2.0);
// CHECK: store volatile float 1.000000e+00, ptr %resf

resd = __builtin_fminimum_num(D, D);
// CHECK: call double @llvm.minimumnum.f64

resd = __builtin_fminimum_num(I, I);
// CHECK: sitofp i32 {{%[0-9]+}} to double
// CHECK: sitofp i32 {{%[0-9]+}} to double
// CHECK: call double @llvm.minimumnum.f64

resd = __builtin_fminimum_num(1.0, 2.0);
// CHECK: store volatile double 1.000000e+00, ptr %resd

//FIXME: __builtin_fminimum_numl is not supported well yet.
resld = __builtin_fminimum_numl(1.0, 2.0);
// CHECK: store volatile x86_fp80 0xK3FFF8000000000000000, ptr %resld, align 16

resf = __builtin_fmaximum_numf(F, F);
// CHECK: call float @llvm.maximumnum.f32

resf = __builtin_fmaximum_numf(I, I);
// CHECK: sitofp i32 {{%[0-9]+}} to float
// CHECK: sitofp i32 {{%[0-9]+}} to float
// CHECK: call float @llvm.maximumnum.f32

resf = __builtin_fmaximum_numf(1.0, 2.0);
// CHECK: store volatile float 2.000000e+00, ptr %resf

resd = __builtin_fmaximum_num(D, D);
// CHECK: call double @llvm.maximumnum.f64

resd = __builtin_fmaximum_num(I, I);
// CHECK: sitofp i32 {{%[0-9]+}} to double
// CHECK: sitofp i32 {{%[0-9]+}} to double
// CHECK: call double @llvm.maximumnum.f64

resd = __builtin_fmaximum_num(1.0, 2.0);
// CHECK: store volatile double 2.000000e+00, ptr %resd

//FIXME: __builtin_fmaximum_numl is not supported well yet.
resld = __builtin_fmaximum_numl(1.0, 2.0);
// CHECK: store volatile x86_fp80 0xK40008000000000000000, ptr %resld, align 16

resf = __builtin_fabsf(F);
// CHECK: call float @llvm.fabs.f32

Expand Down
33 changes: 33 additions & 0 deletions clang/test/CodeGen/fmaxfmin-invalid-arguments-type.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// RUN: not %clang_cc1 -triple x86_64 %s -fsyntax-only -verify 2>&1 | FileCheck %s --check-prefix=CHECK-ERR

float fminimum_numf (float, float);
double fminimum_num (double, double);
long double fminimum_numl (long double, long double);
float fmaximum_numf (float, float);
double fmaximum_num (double, double);
long double fmaximum_numl (long double, long double);

// CHECK-ERR: passing 'char *' to parameter of incompatible type 'float'
float fmin1(char *a, char *b) {
return fminimum_numf(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'double'
float fmin2(char *a, char *b) {
return fminimum_num(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'long double'
float fmin3(char *a, char *b) {
return fminimum_numl(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'float'
float fmax1(char *a, char *b) {
return fmaximum_numf(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'double'
float fmax2(char *a, char *b) {
return fmaximum_num(a, b);
}
// CHECK-ERR: passing 'char *' to parameter of incompatible type 'long double'
float fmax3(char *a, char *b) {
return fmaximum_numl(a, b);
}
22 changes: 17 additions & 5 deletions clang/test/CodeGen/math-libcalls.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm %s | FileCheck %s --check-prefix=NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 %s | FileCheck %s --check-prefix=NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -ffp-exception-behavior=maytrap %s | FileCheck %s --check-prefix=HAS_MAYTRAP
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm %s | FileCheck %s --check-prefixes=COMMON,NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefixes=COMMON,HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 %s | FileCheck %s --check-prefixes=COMMON,NO__ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -disable-llvm-passes -O2 -fmath-errno %s | FileCheck %s --check-prefixes=COMMON,HAS_ERRNO
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -Wno-implicit-function-declaration -w -o - -emit-llvm -ffp-exception-behavior=maytrap %s | FileCheck %s --check-prefixes=COMMON,HAS_MAYTRAP
// RUN: %clang_cc1 -triple x86_64-unknown-unknown-gnu -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_GNU
// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -Wno-implicit-function-declaration -w -o - -emit-llvm -fmath-errno %s | FileCheck %s --check-prefix=HAS_ERRNO_WIN

Expand Down Expand Up @@ -372,6 +372,18 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
// HAS_MAYTRAP: declare float @llvm.experimental.constrained.minnum.f32(
// HAS_MAYTRAP: declare x86_fp80 @llvm.experimental.constrained.minnum.f80(

fmaximum_num(*d,*d); fmaximum_numf(f,f); fmaximum_numl(*l,*l);

// COMMON: declare double @llvm.maximumnum.f64(double, double) [[READNONE_INTRINSIC]]
// COMMON: declare float @llvm.maximumnum.f32(float, float) [[READNONE_INTRINSIC]]
// COMMON: declare x86_fp80 @llvm.maximumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]

fminimum_num(*d,*d); fminimum_numf(f,f); fminimum_numl(*l,*l);

// COMMON: declare double @llvm.minimumnum.f64(double, double) [[READNONE_INTRINSIC]]
// COMMON: declare float @llvm.minimumnum.f32(float, float) [[READNONE_INTRINSIC]]
// COMMON: declare x86_fp80 @llvm.minimumnum.f80(x86_fp80, x86_fp80) [[READNONE_INTRINSIC]]

hypot(f,f); hypotf(f,f); hypotl(f,f);

// NO__ERRNO: declare double @hypot(double noundef, double noundef) [[READNONE]]
Expand Down
5 changes: 2 additions & 3 deletions clang/test/Driver/avr-mmcu.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// A test for the propagation of the -mmcu option to -cc1 and -cc1as

// RUN: %clang -### --target=avr -mmcu=attiny11 -save-temps %s 2>&1 | FileCheck -check-prefix=CHECK0 %s
// CHECK0: "-cc1" {{.*}} "-target-cpu" "attiny11"
// CHECK0: "-cc1as" {{.*}} "-target-cpu" "attiny11"
// RUN: not %clang -### --target=avr -mmcu=attiny11 %s 2>&1 | FileCheck -check-prefix=CHECK0 %s
// CHECK0: error: '-mmcu=attiny11' invalid for input of type c/c++

// RUN: %clang -### --target=avr -mmcu=at90s2313 -save-temps %s 2>&1 | FileCheck -check-prefix=CHECK1 %s
// CHECK1: "-cc1" {{.*}} "-target-cpu" "at90s2313"
Expand Down
6 changes: 3 additions & 3 deletions clang/test/Driver/hip-link-save-temps.hip
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
// CHECK-NOT: {{".*/opt"}}
// CHECK-NOT: {{".*/llc"}}
// CHECK: "{{.*lld.*}}" {{.*}} "-plugin-opt=-amdgpu-internalize-symbols"
// CHECK-SAME: "-o" "a.out-hip-amdgcn-amd-amdhsa-gfx900" "obj1-hip-amdgcn-amd-amdhsa-gfx900.o" "obj2-hip-amdgcn-amd-amdhsa-gfx900.o"
// CHECK-SAME: "-o" "[[HIPFB1:.+]]" "obj1-hip-amdgcn-amd-amdhsa-gfx900.o" "obj2-hip-amdgcn-amd-amdhsa-gfx900.o"
// CHECK: "{{.*lld.*}}" {{.*}} "-plugin-opt=-amdgpu-internalize-symbols"
// CHECK-SAME: "-o" "a.out-hip-amdgcn-amd-amdhsa-gfx906" "obj1-hip-amdgcn-amd-amdhsa-gfx906.o" "obj2-hip-amdgcn-amd-amdhsa-gfx906.o"
// CHECK: {{".*llvm-mc.*"}} "-o" "[[OBJBUNDLE:.*.o]]" "{{.*}}.mcin" "--filetype=obj"
// CHECK-SAME: "-o" "[[HIPFB2:.+]]" "obj1-hip-amdgcn-amd-amdhsa-gfx906.o" "obj2-hip-amdgcn-amd-amdhsa-gfx906.o"
// CHECK: "{{.*clang.*}}" "-target" "x86_64-unknown-linux-gnu" "-o" "[[OBJBUNDLE:.+.o]]" "-x" "assembler" "{{.*}}.mcin" "-c"
// OUT: "{{.*ld.*}}" {{.*}} "-o" "executable" {{.*}} "[[OBJBUNDLE]]"
// NOUT: "{{.*ld.*}}" {{.*}} "-o" "a.out" {{.*}} "[[OBJBUNDLE]]"
// SLO: "{{.*llvm-ar.*}}" "rcsD" "libTest.a" {{.*}} "[[OBJBUNDLE]]"
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/hip-partial-link.hip
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
// LD-R: "{{.*}}/clang-offload-bundler" {{.*}}-unbundle
// LD-R: "{{.*}}/lld" -flavor gnu -m elf64_amdgpu
// LD-R: "{{.*}}/clang-offload-bundler"
// LD-R: "{{.*}}/llvm-mc" -triple x86_64-unknown-linux-gnu
// LD-R: "{{.*}}/clang{{.*}}" -target x86_64-unknown-linux-gnu
// LD-R: "{{.*}}/ld.lld" {{.*}} -r

// RUN: llvm-nm %t.lib.o | FileCheck -check-prefix=OBJ %s
Expand Down Expand Up @@ -65,7 +65,7 @@
// STATIC: "{{.*}}/clang-offload-bundler" {{.*}}-unbundle
// STATIC: "{{.*}}/lld" -flavor gnu -m elf64_amdgpu
// STATIC: "{{.*}}/clang-offload-bundler"
// STATIC: "{{.*}}/llvm-mc" -triple x86_64-unknown-linux-gnu
// STATIC: "{{.*}}/clang{{.*}}" -target x86_64-unknown-linux-gnu
// STATIC: "{{.*}}/llvm-ar"

// RUN: %clang -v --target=x86_64-unknown-linux-gnu --no-offload-new-driver \
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/hip-save-temps.hip
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
// RDCC: "{{.*clang.*}}" "-cc1as" {{.*}} "-o" "hip-save-temps-host-x86_64-unknown-linux-gnu.o"
// RDCC: "{{.*clang-offload-bundler.*}}" {{.*}} "-output=hip-save-temps.o"
// RDCL: "{{.*clang-offload-bundler.*}}" {{.*}} "-output=hip-save-temps-hip-amdgcn-amd-amdhsa.hipfb"
// RDCL: {{.*}}llvm-mc{{.*}}"-o" "hip-save-temps-hip-amdgcn-amd-amdhsa.o" "hip-save-temps-hip-amdgcn-amd-amdhsa.mcin" "--filetype=obj"
// RDCL: "{{.*clang.*}}" "-target" "x86_64-unknown-linux-gnu" "-o" "{{.*}}.o" "-x" "assembler" "{{.*}}.mcin" "-c"

// -fno-gpu-rdc host object path
// NORDC: "{{.*clang.*}}" "-cc1" {{.*}} "-E" {{.*}} "-o" "hip-save-temps-host-x86_64-unknown-linux-gnu.hipi"
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Driver/hip-toolchain-rdc-separate.hip
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@
// LINK-BUNDLE-SAME: "-input={{.*}}" "-input=[[IMG_DEV1]]" "-input=[[IMG_DEV2]]" "-output=[[BUNDLE:.*]]"
// LINK-NOBUNDLE-NOT: {{".*clang-offload-bundler"}} "-type=o"

// LINK-EMBED: {{".*llvm-mc.*"}} "-o" "[[OBJBUNDLE:.*o]]" "{{.*}}.mcin" "--filetype=obj"
// LINK-NOEMBED-NOT: {{".*llvm-mc.*"}} "-o"
// LINK-EMBED: {{".*clang.*"}} "-o" "[[OBJBUNDLE:.*o]]" "{{.*}}.mcin"
// LINK-NOEMBED-NOT: {{".*clang.*"}} "-o"

// LINK-EMBED: [[LD:".*ld.*"]] {{.*}} "-o" "a.out" {{.*}} "[[A_OBJ_HOST]]"
// LINK-EMBED-SAME: "[[B_OBJ_HOST]]" "[[OBJBUNDLE]]"
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/hip-toolchain-rdc-static-lib.hip
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,6 @@
// CHECK-SAME: "-targets={{.*}},hipv4-amdgcn-amd-amdhsa--gfx803,hipv4-amdgcn-amd-amdhsa--gfx900"
// CHECK-SAME: "-input=[[IMG_DEV1]]" "-input=[[IMG_DEV2]]" "-output=[[BUNDLE:.*hipfb]]"

// CHECK: [[MC:".*llvm-mc.*"]] "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin" "--filetype=obj"
// CHECK: [[MC:".*clang.*"]] "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin"

// CHECK: [[AR:".*llvm-ar.*"]] "rcsD" "{{.*}}.out" [[A_OBJ_HOST]] [[B_OBJ_HOST]] [[OBJBUNDLE]]
2 changes: 1 addition & 1 deletion clang/test/Driver/hip-toolchain-rdc.hip
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
// CHECK-SAME: "-targets={{.*}},hipv4-amdgcn-amd-amdhsa--gfx803,hipv4-amdgcn-amd-amdhsa--gfx900"
// CHECK-SAME: "-input={{.*}}" "-input=[[IMG_DEV1]]" "-input=[[IMG_DEV2]]" "-output=[[BUNDLE]]"

// CHECK: [[MC:".*llvm-mc.*"]] "-triple" [[HOST]] "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin" "--filetype=obj"
// CHECK: [[MC:".*clang.*"]] "-target" [[HOST]] "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin"

// output the executable
// LNX: [[LD:".*ld.*"]] {{.*}}"-o" "a.out" {{.*}} [[A_OBJ_HOST]] [[B_OBJ_HOST]] [[OBJBUNDLE]]
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/hip-unbundle-preproc.hipi
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@
// RDC: {{".*clang.*"}} "-cc1" {{.*}}"-target-cpu" "gfx803" {{.*}}"-o" "[[DEV_BC:.*bc]]" {{.*}}"[[DEV_PP]]"
// RDC: {{".*lld.*"}} {{.*}}"-o" "[[DEV_ISA:.*]]" "[[DEV_BC]]"
// RDC: {{".*clang-offload-bundler.*"}} {{.*}}"-input={{.*}}" "-input=[[DEV_ISA]]" "-output=[[FATBIN:.*]]"
// RDC: {{".*llvm-mc.*"}} "-o" "[[FATBIN_O:.*o]]"
// RDC: {{".*clang.*"}} "-o" "[[FATBIN_O:.*o]]"
// RDC: {{".*ld.*"}} {{.*}}"[[HOST_O]]" "[[FATBIN_O]]"
3 changes: 1 addition & 2 deletions clang/test/Driver/hipspv-toolchain-rdc.hip
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@
// CHECK-SAME: "-targets={{.*}},hip-spirv64----generic"
// CHECK-SAME: "-input=/dev/null" "-input=[[AB_SPIRV]]"
// CHECK-SAME: "-output=[[AB_FATBIN:.*hipfb]]"
// CHECK: {{".*llvm-mc.*"}} "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin"
// CHECK-SAME: "--filetype=obj"
// CHECK: {{".*clang.*"}} "-o" [[OBJBUNDLE:".*o"]] "{{.*}}.mcin"

// Output the executable
// CHECK: {{".*ld.*"}} {{.*}}"-o" "a.out" {{.*}} [[A_OBJ_HOST]] [[B_OBJ_HOST]]
Expand Down
52 changes: 45 additions & 7 deletions clang/test/Frontend/plugin-attribute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,57 @@
// REQUIRES: plugins, examples
//--- good_attr.cpp
// expected-no-diagnostics
void fn1a() __attribute__((example)) {}
[[example]] void fn1b() {}
[[plugin::example]] void fn1c() {}
void fn2() __attribute__((example("somestring", 1, 2.0))) {}
// CHECK-COUNT-4: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "example"
void fn1a() __attribute__((example)) {
__attribute__((example)) for (int i = 0; i < 9; ++i) {}
}
[[example]] void fn1b() {
[[example]] for (int i = 0; i < 9; ++i) {}
}
[[plugin::example]] void fn1c() {
[[plugin::example]] for (int i = 0; i < 9; ++i) {}
}
void fn2() __attribute__((example("somestring", 1, 2.0))) {
__attribute__((example("abc", 3, 4.0))) for (int i = 0; i < 9; ++i) {}
}
template <int N> void template_fn() __attribute__((example("template", N))) {
__attribute__((example("def", N + 1))) for (int i = 0; i < 9; ++i) {}
}
void fn3() { template_fn<5>(); }
// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -AttributedStmt 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}}
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "abc"
// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 3
// CHECK: -FloatingLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'double' 4.000000e+00
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "somestring"
// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 1
// CHECK: -FloatingLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'double' 2.000000e+00
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} Implicit "example"
// CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "def"
// CHECK: -BinaryOperator 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' '+'
// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} 'int' 5
// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 1
// CHECK: -AnnotateAttr 0x{{[0-9a-z]+}} {{<line:[0-9]+:[0-9]+(, col:[0-9]+)?>}} "example"
// CHECK: -StringLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'const char[{{[0-9]+}}]' lvalue "template"
// CHECK: -IntegerLiteral 0x{{[0-9a-z]+}} {{<col:[0-9]+(, col:[0-9]+)?>}} 'int' 5

//--- bad_attr.cpp
int var1 __attribute__((example("otherstring"))) = 1; // expected-warning {{'example' attribute only applies to functions}}
class Example {
void __attribute__((example)) fn3(); // expected-error {{'example' attribute only allowed at file scope}}
};
void fn4() __attribute__((example(123))) { } // expected-error {{first argument to the 'example' attribute must be a string literal}}
void fn5() __attribute__((example("a","b", 3, 4.0))) { } // expected-error {{'example' attribute only accepts at most three arguments}}
void fn4() __attribute__((example(123))) { // expected-error {{first argument to the 'example' attribute must be a string literal}}
__attribute__((example("somestring"))) while (true); // expected-warning {{'example' attribute only applies to for loop statements}}
}
void fn5() __attribute__((example("a","b", 3, 4.0))) { // expected-error {{'example' attribute only accepts at most three arguments}}
__attribute__((example("a","b", 3, 4.0))) for (int i = 0; i < 10; ++i) {} // expected-error {{'example' attribute only accepts at most three arguments}}
}
4 changes: 3 additions & 1 deletion clang/test/Preprocessor/feature_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@

// Check __has_constexpr_builtin
#if !__has_constexpr_builtin(__builtin_fmax) || \
!__has_constexpr_builtin(__builtin_fmin)
!__has_constexpr_builtin(__builtin_fmin) || \
!__has_constexpr_builtin(__builtin_fmaximum_num) || \
!__has_constexpr_builtin(__builtin_fminimum_num)
#error Clang should have these constexpr builtins
#endif

Expand Down
12 changes: 12 additions & 0 deletions clang/test/Preprocessor/time64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: %clang_cc1 -E -dM -triple=i686-pc-linux-gnu /dev/null | FileCheck -match-full-lines -check-prefix TIME32 %s
// RUN: %clang_cc1 -E -dM -triple=i686-pc-linux-gnut64 /dev/null | FileCheck -match-full-lines -check-prefix TIME64 %s
// RUN: %clang_cc1 -E -dM -triple=armv5tel-softfloat-linux-gnueabi /dev/null | FileCheck -match-full-lines -check-prefix TIME32 %s
// RUN: %clang_cc1 -E -dM -triple=armv5tel-softfloat-linux-gnueabit64 /dev/null | FileCheck -match-full-lines -check-prefix TIME64 %s
// RUN: %clang_cc1 -E -dM -triple=armv7a-unknown-linux-gnueabihf /dev/null | FileCheck -match-full-lines -check-prefix TIME32 %s
// RUN: %clang_cc1 -E -dM -triple=armv7a-unknown-linux-gnueabihft64 /dev/null | FileCheck -match-full-lines -check-prefix TIME64 %s
//
// TIME32-NOT:#define _FILE_OFFSET_BITS 64
// TIME32-NOT:#define _TIME_BITS 64
//
// TIME64:#define _FILE_OFFSET_BITS 64
// TIME64:#define _TIME_BITS 64
69 changes: 69 additions & 0 deletions clang/test/Sema/constant-builtins-fmaximum-num.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
// FIXME: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

constexpr double NaN = __builtin_nan("");
constexpr double SNaN = __builtin_nans("");
constexpr double Inf = __builtin_inf();
constexpr double NegInf = -__builtin_inf();

#define FMAXIMUMNUM_TEST_SIMPLE(T, FUNC) \
static_assert(T(6.7890) == FUNC(T(1.2345), T(6.7890))); \
static_assert(T(6.7890) == FUNC(T(6.7890), T(1.2345)));

#define FMAXIMUMNUM_TEST_SNAN(T, FUNC) \
static_assert(Inf == FUNC(SNaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, SNaN)); \
static_assert(0.0 == FUNC(SNaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, SNaN)); \
static_assert(T(-1.2345) == FUNC(SNaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), SNaN)); \
static_assert(__builtin_isnan(FUNC(SNaN, SNaN))); \
static_assert(__builtin_isnan(FUNC(NaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(SNaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(NaN, SNaN)));

#define FMAXIMUMNUM_TEST_NAN(T, FUNC) \
static_assert(Inf == FUNC(NaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, NaN)); \
static_assert(0.0 == FUNC(NaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, NaN)); \
static_assert(T(-1.2345) == FUNC(NaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), NaN)); \
static_assert(__builtin_isnan(FUNC(NaN, NaN)));

#define FMAXIMUMNUM_TEST_INF(T, FUNC) \
static_assert(Inf == FUNC(NegInf, Inf)); \
static_assert(Inf == FUNC(Inf, 0.0)); \
static_assert(Inf == FUNC(-0.0, Inf)); \
static_assert(Inf == FUNC(Inf, T(1.2345))); \
static_assert(Inf == FUNC(T(-1.2345), Inf));

#define FMAXIMUMNUM_TEST_NEG_INF(T, FUNC) \
static_assert(Inf == FUNC(Inf, NegInf)); \
static_assert(0.0 == FUNC(NegInf, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, NegInf)); \
static_assert(T(-1.2345) == FUNC(NegInf, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), NegInf));

#define FMAXIMUMNUM_TEST_BOTH_ZERO(T, FUNC) \
static_assert(__builtin_copysign(1.0, FUNC(0.0, 0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, 0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(0.0, -0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, -0.0)) == -1.0);

#define LIST_FMAXIMUMNUM_TESTS(T, FUNC) \
FMAXIMUMNUM_TEST_SIMPLE(T, FUNC) \
FMAXIMUMNUM_TEST_NAN(T, FUNC) \
FMAXIMUMNUM_TEST_SNAN(T, FUNC) \
FMAXIMUMNUM_TEST_INF(T, FUNC) \
FMAXIMUMNUM_TEST_NEG_INF(T, FUNC) \
FMAXIMUMNUM_TEST_BOTH_ZERO(T, FUNC)

LIST_FMAXIMUMNUM_TESTS(double, __builtin_fmaximum_num)
LIST_FMAXIMUMNUM_TESTS(float, __builtin_fmaximum_numf)
LIST_FMAXIMUMNUM_TESTS((long double), __builtin_fmaximum_numl)
LIST_FMAXIMUMNUM_TESTS(__fp16, __builtin_fmaximum_numf16)
#ifdef __FLOAT128__
LIST_FMAXIMUMNUM_TESTS(__float128, __builtin_fmaximum_numf128)
#endif
69 changes: 69 additions & 0 deletions clang/test/Sema/constant-builtins-fminimum-num.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
// FIXME: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s
// expected-no-diagnostics

constexpr double NaN = __builtin_nan("");
constexpr double SNaN = __builtin_nans("");
constexpr double Inf = __builtin_inf();
constexpr double NegInf = -__builtin_inf();

#define FMINIMUMNUM_TEST_SIMPLE(T, FUNC) \
static_assert(T(1.2345) == FUNC(T(1.2345), T(6.7890))); \
static_assert(T(1.2345) == FUNC(T(6.7890), T(1.2345)));

#define FMINIMUMNUM_TEST_NAN(T, FUNC) \
static_assert(Inf == FUNC(NaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, NaN)); \
static_assert(0.0 == FUNC(NaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, NaN)); \
static_assert(T(-1.2345) == FUNC(NaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), NaN)); \
static_assert(__builtin_isnan(FUNC(NaN, NaN)));

#define FMINIMUMNUM_TEST_SNAN(T, FUNC) \
static_assert(Inf == FUNC(SNaN, Inf)); \
static_assert(NegInf == FUNC(NegInf, SNaN)); \
static_assert(0.0 == FUNC(SNaN, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, SNaN)); \
static_assert(T(-1.2345) == FUNC(SNaN, T(-1.2345))); \
static_assert(T(1.2345) == FUNC(T(1.2345), SNaN)); \
static_assert(__builtin_isnan(FUNC(SNaN, SNaN))); \
static_assert(__builtin_isnan(FUNC(NaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(SNaN, SNaN))); \
static_assert(!__builtin_issignaling(FUNC(NaN, SNaN)));

#define FMINIMUMNUM_TEST_INF(T, FUNC) \
static_assert(NegInf == FUNC(NegInf, Inf)); \
static_assert(0.0 == FUNC(Inf, 0.0)); \
static_assert(-0.0 == FUNC(-0.0, Inf)); \
static_assert(T(1.2345) == FUNC(Inf, T(1.2345))); \
static_assert(T(-1.2345) == FUNC(T(-1.2345), Inf));

#define FMINIMUMNUM_TEST_NEG_INF(T, FUNC) \
static_assert(NegInf == FUNC(Inf, NegInf)); \
static_assert(NegInf == FUNC(NegInf, 0.0)); \
static_assert(NegInf == FUNC(-0.0, NegInf)); \
static_assert(NegInf == FUNC(NegInf, T(-1.2345))); \
static_assert(NegInf == FUNC(T(1.2345), NegInf));

#define FMINIMUMNUM_TEST_BOTH_ZERO(T, FUNC) \
static_assert(__builtin_copysign(1.0, FUNC(0.0, 0.0)) == 1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, 0.0)) == -1.0); \
static_assert(__builtin_copysign(1.0, FUNC(0.0, -0.0)) == -1.0); \
static_assert(__builtin_copysign(1.0, FUNC(-0.0, -0.0)) == -1.0);

#define LIST_FMINIMUMNUM_TESTS(T, FUNC) \
FMINIMUMNUM_TEST_SIMPLE(T, FUNC) \
FMINIMUMNUM_TEST_NAN(T, FUNC) \
FMINIMUMNUM_TEST_SNAN(T, FUNC) \
FMINIMUMNUM_TEST_INF(T, FUNC) \
FMINIMUMNUM_TEST_NEG_INF(T, FUNC) \
FMINIMUMNUM_TEST_BOTH_ZERO(T, FUNC)

LIST_FMINIMUMNUM_TESTS(double, __builtin_fminimum_num)
LIST_FMINIMUMNUM_TESTS(float, __builtin_fminimum_numf)
LIST_FMINIMUMNUM_TESTS((long double), __builtin_fminimum_numl)
LIST_FMINIMUMNUM_TESTS(__fp16, __builtin_fminimum_numf16)
#ifdef __FLOAT128__
LIST_FMINIMUMNUM_TESTS(__float128, __builtin_fminimum_numf128)
#endif
3 changes: 3 additions & 0 deletions clang/test/SemaCXX/block-packs.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fsyntax-only -verify -Wno-unused %s
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fsyntax-only -verify -Wno-unused %s -frecovery-ast -frecovery-ast-type

// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fsyntax-only -verify -Wno-unused -fexperimental-new-constant-interpreter %s
// RUN: %clang_cc1 -fblocks -triple x86_64-apple-darwin -fsyntax-only -verify -Wno-unused -frecovery-ast -frecovery-ast-type -fexperimental-new-constant-interpreter %s

template <typename ...Ts>
void f() {
((^ { Ts t; }), ...);
Expand Down
Loading