Skip to content

Commit

Permalink
merge main into amd-staging
Browse files Browse the repository at this point in the history
Change-Id: Ic06cc3c184b4ec6abb5279499c64cf0b0068cab8
  • Loading branch information
Jenkins committed Jan 20, 2024
2 parents 8c6d9a9 + 0880742 commit b04df36
Show file tree
Hide file tree
Showing 39 changed files with 765 additions and 219 deletions.
56 changes: 41 additions & 15 deletions clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@

#include "UseAutoCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/TypeLoc.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Tooling/FixIt.h"
#include "llvm/ADT/STLExtras.h"

using namespace clang;
using namespace clang::ast_matchers;
Expand Down Expand Up @@ -333,6 +335,25 @@ void UseAutoCheck::replaceIterators(const DeclStmt *D, ASTContext *Context) {
<< FixItHint::CreateReplacement(Range, "auto");
}

static void ignoreTypeLocClasses(
TypeLoc &Loc,
std::initializer_list<TypeLoc::TypeLocClass> const &LocClasses) {
while (llvm::is_contained(LocClasses, Loc.getTypeLocClass()))
Loc = Loc.getNextTypeLoc();
}

static bool isMutliLevelPointerToTypeLocClasses(
TypeLoc Loc,
std::initializer_list<TypeLoc::TypeLocClass> const &LocClasses) {
ignoreTypeLocClasses(Loc, {TypeLoc::Paren, TypeLoc::Qualified});
TypeLoc::TypeLocClass TLC = Loc.getTypeLocClass();
if (TLC != TypeLoc::Pointer && TLC != TypeLoc::MemberPointer)
return false;
ignoreTypeLocClasses(Loc, {TypeLoc::Paren, TypeLoc::Qualified,
TypeLoc::Pointer, TypeLoc::MemberPointer});
return llvm::is_contained(LocClasses, Loc.getTypeLocClass());
}

void UseAutoCheck::replaceExpr(
const DeclStmt *D, ASTContext *Context,
llvm::function_ref<QualType(const Expr *)> GetType, StringRef Message) {
Expand All @@ -342,6 +363,10 @@ void UseAutoCheck::replaceExpr(
return;

const QualType FirstDeclType = FirstDecl->getType().getCanonicalType();
TypeSourceInfo *TSI = FirstDecl->getTypeSourceInfo();

if (TSI == nullptr)
return;

std::vector<FixItHint> StarRemovals;
for (const auto *Dec : D->decls()) {
Expand Down Expand Up @@ -383,17 +408,11 @@ void UseAutoCheck::replaceExpr(
// is the same as the initializer, just more CV-qualified. However, TypeLoc
// information is not reliable where CV qualifiers are concerned so we can't
// do anything about this case for now.
TypeLoc Loc = FirstDecl->getTypeSourceInfo()->getTypeLoc();
if (!RemoveStars) {
while (Loc.getTypeLocClass() == TypeLoc::Pointer ||
Loc.getTypeLocClass() == TypeLoc::Qualified)
Loc = Loc.getNextTypeLoc();
}
while (Loc.getTypeLocClass() == TypeLoc::LValueReference ||
Loc.getTypeLocClass() == TypeLoc::RValueReference ||
Loc.getTypeLocClass() == TypeLoc::Qualified) {
Loc = Loc.getNextTypeLoc();
}
TypeLoc Loc = TSI->getTypeLoc();
if (!RemoveStars)
ignoreTypeLocClasses(Loc, {TypeLoc::Pointer, TypeLoc::Qualified});
ignoreTypeLocClasses(Loc, {TypeLoc::LValueReference, TypeLoc::RValueReference,
TypeLoc::Qualified});
SourceRange Range(Loc.getSourceRange());

if (MinTypeNameLength != 0 &&
Expand All @@ -405,12 +424,19 @@ void UseAutoCheck::replaceExpr(

auto Diag = diag(Range.getBegin(), Message);

bool ShouldReplenishVariableName = isMutliLevelPointerToTypeLocClasses(
TSI->getTypeLoc(), {TypeLoc::FunctionProto, TypeLoc::ConstantArray});

// Space after 'auto' to handle cases where the '*' in the pointer type is
// next to the identifier. This avoids changing 'int *p' into 'autop'.
// FIXME: This doesn't work for function pointers because the variable name
// is inside the type.
Diag << FixItHint::CreateReplacement(Range, RemoveStars ? "auto " : "auto")
<< StarRemovals;
llvm::StringRef Auto = ShouldReplenishVariableName
? (RemoveStars ? "auto " : "auto *")
: (RemoveStars ? "auto " : "auto");
std::string ReplenishedVariableName =
ShouldReplenishVariableName ? FirstDecl->getQualifiedNameAsString() : "";
std::string Replacement =
(Auto + llvm::StringRef{ReplenishedVariableName}).str();
Diag << FixItHint::CreateReplacement(Range, Replacement) << StarRemovals;
}

void UseAutoCheck::check(const MatchFinder::MatchResult &Result) {
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,10 @@ Changes in existing checks
false-positives when constructing the container with ``count`` copies of
elements with value ``value``.

- Improved :doc:`modernize-use-auto
<clang-tidy/checks/modernize/use-auto>` to avoid create incorrect fix hints
for pointer to array type and pointer to function type.

- Improved :doc:`modernize-use-emplace
<clang-tidy/checks/modernize/use-emplace>` to not replace aggregates that
``emplace`` cannot construct with aggregate initialization.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// RUN: %check_clang_tidy -check-suffix=REMOVE %s modernize-use-auto %t -- \
// RUN: -config="{CheckOptions: {modernize-use-auto.RemoveStars: 'true', modernize-use-auto.MinTypeNameLength: '0'}}"
// RUN: %check_clang_tidy %s modernize-use-auto %t -- \
// RUN: -config="{CheckOptions: {modernize-use-auto.RemoveStars: 'false', modernize-use-auto.MinTypeNameLength: '0'}}"

void pointerToFunction() {
void (*(*(f1)))() = static_cast<void (**)()>(nullptr);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing
// CHECK-FIXES-REMOVE: auto f1 =
// CHECK-FIXES: auto *f1 =
}

void pointerToArray() {
int(*a1)[2] = new int[10][2];
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing
// CHECK-FIXES-REMOVE: auto a1 =
// CHECK-FIXES: auto *a1 =
}

void memberFunctionPointer() {
class A {
void f();
};
void(A::* a1)() = static_cast<void(A::*)()>(nullptr);
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use auto when initializing
// CHECK-FIXES-REMOVE: auto a1 =
// CHECK-FIXES: auto *a1 =
}

2 changes: 1 addition & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ Improvements to Clang's diagnostics
and template friend declarations with a constraint that depends on a template parameter from an
enclosing template must be a definition.
- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``.

- Clang now diagnoses incorrect usage of ``const`` and ``pure`` attributes, so ``-Wignored-attributes`` diagnoses more cases.
- Clang now emits more descriptive diagnostics for 'unusual' expressions (e.g. incomplete index
expressions on matrix types or builtin functions without an argument list) as placement-args
to new-expressions.
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3621,7 +3621,7 @@ Attribute ``trivial_abi`` has no effect in the following cases:

def MSInheritanceDocs : Documentation {
let Category = DocCatDecl;
let Heading = "__single_inhertiance, __multiple_inheritance, __virtual_inheritance";
let Heading = "__single_inheritance, __multiple_inheritance, __virtual_inheritance";
let Content = [{
This collection of keywords is enabled under ``-fms-extensions`` and controls
the pointer-to-member representation used on ``*-*-win32`` targets.
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,13 @@ def warn_maybe_falloff_nonvoid_function : Warning<
def warn_falloff_nonvoid_function : Warning<
"non-void function does not return a value">,
InGroup<ReturnType>;
def warn_const_attr_with_pure_attr : Warning<
"'const' attribute imposes more restrictions; 'pure' attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_pure_function_returns_void : Warning<
"'%select{pure|const}0' attribute on function returning 'void'; attribute ignored">,
InGroup<IgnoredAttributes>;

def err_maybe_falloff_nonvoid_block : Error<
"non-void block does not return a value in all control paths">;
def err_falloff_nonvoid_block : Error<
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Sema/ScopeInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ namespace sema {
/// parsed.
class CompoundScopeInfo {
public:
/// Whether this compound stamement contains `for' or `while' loops
/// Whether this compound statement contains `for' or `while' loops
/// with empty bodies.
bool HasEmptyLoopBodies = false;

Expand Down Expand Up @@ -168,7 +168,7 @@ class FunctionScopeInfo {
/// to build, the initial and final coroutine suspend points
bool NeedsCoroutineSuspends : 1;

/// An enumeration represeting the kind of the first coroutine statement
/// An enumeration representing the kind of the first coroutine statement
/// in the function. One of co_return, co_await, or co_yield.
unsigned char FirstCoroutineStmtKind : 2;

Expand Down Expand Up @@ -220,7 +220,7 @@ class FunctionScopeInfo {
/// The initial and final coroutine suspend points.
std::pair<Stmt *, Stmt *> CoroutineSuspends;

/// The stack of currently active compound stamement scopes in the
/// The stack of currently active compound statement scopes in the
/// function.
SmallVector<CompoundScopeInfo, 4> CompoundScopes;

Expand Down
42 changes: 41 additions & 1 deletion clang/lib/Format/FormatTokenLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,10 @@ ArrayRef<FormatToken *> FormatTokenLexer::lex() {
// string literals are correctly identified.
handleCSharpVerbatimAndInterpolatedStrings();
}
if (Style.isTableGen())
if (Style.isTableGen()) {
handleTableGenMultilineString();
handleTableGenNumericLikeIdentifier();
}
if (Tokens.back()->NewlinesBefore > 0 || Tokens.back()->IsMultiline)
FirstInLineIndex = Tokens.size() - 1;
} while (Tokens.back()->isNot(tok::eof));
Expand Down Expand Up @@ -804,6 +806,44 @@ void FormatTokenLexer::handleTableGenMultilineString() {
FirstLineText, MultiLineString->OriginalColumn, Style.TabWidth, Encoding);
}

void FormatTokenLexer::handleTableGenNumericLikeIdentifier() {
FormatToken *Tok = Tokens.back();
// TableGen identifiers can begin with digits. Such tokens are lexed as
// numeric_constant now.
if (Tok->isNot(tok::numeric_constant))
return;
StringRef Text = Tok->TokenText;
// The following check is based on llvm::TGLexer::LexToken.
// That lexes the token as a number if any of the following holds:
// 1. It starts with '+', '-'.
// 2. All the characters are digits.
// 3. The first non-digit character is 'b', and the next is '0' or '1'.
// 4. The first non-digit character is 'x', and the next is a hex digit.
// Note that in the case 3 and 4, if the next character does not exists in
// this token, the token is an identifier.
if (Text.size() < 1 || Text[0] == '+' || Text[0] == '-')
return;
const auto NonDigitPos = Text.find_if([](char C) { return !isdigit(C); });
// All the characters are digits
if (NonDigitPos == StringRef::npos)
return;
char FirstNonDigit = Text[NonDigitPos];
if (NonDigitPos < Text.size() - 1) {
char TheNext = Text[NonDigitPos + 1];
// Regarded as a binary number.
if (FirstNonDigit == 'b' && (TheNext == '0' || TheNext == '1'))
return;
// Regarded as hex number.
if (FirstNonDigit == 'x' && isxdigit(TheNext))
return;
}
if (isalpha(FirstNonDigit) || FirstNonDigit == '_') {
// This is actually an identifier in TableGen.
Tok->Tok.setKind(tok::identifier);
Tok->Tok.setIdentifierInfo(nullptr);
}
}

void FormatTokenLexer::handleTemplateStrings() {
FormatToken *BacktickToken = Tokens.back();

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Format/FormatTokenLexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ class FormatTokenLexer {

// Handles TableGen multiline strings. It has the form [{ ... }].
void handleTableGenMultilineString();
// Handles TableGen numeric like identifiers.
// They have a forms of [0-9]*[_a-zA-Z]([_a-zA-Z0-9]*). But limited to the
// case it is not lexed as an integer.
void handleTableGenNumericLikeIdentifier();

void tryParsePythonComment();

Expand Down
28 changes: 28 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11801,6 +11801,32 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
OldDecl, Previous);
}

static void CheckConstPureAttributesUsage(Sema &S, FunctionDecl *NewFD) {
bool IsPure = NewFD->hasAttr<PureAttr>();
bool IsConst = NewFD->hasAttr<ConstAttr>();

// If there are no pure or const attributes, there's nothing to check.
if (!IsPure && !IsConst)
return;

// If the function is marked both pure and const, we retain the const
// attribute because it makes stronger guarantees than the pure attribute, and
// we drop the pure attribute explicitly to prevent later confusion about
// semantics.
if (IsPure && IsConst) {
S.Diag(NewFD->getLocation(), diag::warn_const_attr_with_pure_attr);
NewFD->dropAttrs<PureAttr>();
}

// Constructors and destructors are functions which return void, so are
// handled here as well.
if (NewFD->getReturnType()->isVoidType()) {
S.Diag(NewFD->getLocation(), diag::warn_pure_function_returns_void)
<< IsConst;
NewFD->dropAttrs<PureAttr, ConstAttr>();
}
}

/// Perform semantic checking of a new function declaration.
///
/// Performs semantic analysis of the new function declaration
Expand Down Expand Up @@ -11898,6 +11924,8 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
NewFD->setInvalidDecl();
}

CheckConstPureAttributesUsage(*this, NewFD);

// C++11 [dcl.constexpr]p8:
// A constexpr specifier for a non-static member function that is not
// a constructor declares that member function to be const.
Expand Down
8 changes: 4 additions & 4 deletions clang/test/Analysis/call-invalidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ void testConstReferenceStruct() {
}


void usePointerPure(int * const *) __attribute__((pure));
void usePointerConst(int * const *) __attribute__((const));
int usePointerPure(int * const *) __attribute__((pure));
int usePointerConst(int * const *) __attribute__((const));

void testPureConst() {
extern int global;
Expand All @@ -104,11 +104,11 @@ void testPureConst() {
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
clang_analyzer_eval(global == -5); // expected-warning{{TRUE}}

usePointerPure(&p);
(void)usePointerPure(&p);
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
clang_analyzer_eval(global == -5); // expected-warning{{TRUE}}

usePointerConst(&p);
(void)usePointerConst(&p);
clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
clang_analyzer_eval(global == -5); // expected-warning{{TRUE}}

Expand Down
6 changes: 3 additions & 3 deletions clang/test/CodeGen/function-attributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ int f12(int arg) {
return arg ? 0 : f10_t();
}

// CHECK: define{{.*}} void @f13() [[NUW_OS_RN:#[0-9]+]]
void f13(void) __attribute__((pure)) __attribute__((const));
void f13(void){}
// CHECK: define{{.*}} i32 @f13() [[NUW_OS_RN:#[0-9]+]]
int f13(void) __attribute__((const));
int f13(void){ return 0; }


// [irgen] clang isn't setting the optsize bit on functions
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CodeGen/pragma-weak.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// CHECK-DAG: @declfirstattr = weak{{.*}} alias void (), ptr @__declfirstattr
// CHECK-DAG: @mix2 = weak{{.*}} alias void (), ptr @__mix2
// CHECK-DAG: @a1 = weak{{.*}} alias void (), ptr @__a1
// CHECK-DAG: @xxx = weak{{.*}} alias void (), ptr @__xxx
// CHECK-DAG: @xxx = weak{{.*}} alias i32 (), ptr @__xxx
// CHECK-DAG: @undecfunc_alias1 = weak{{.*}} alias void (), ptr @undecfunc
// CHECK-DAG: @undecfunc_alias2 = weak{{.*}} alias void (), ptr @undecfunc
// CHECK-DAG: @undecfunc_alias3 = weak{{.*}} alias void (), ptr @undecfunc
Expand Down Expand Up @@ -137,8 +137,8 @@ void __a1(void) {}
// CHECK: define{{.*}} void @__a1() [[NI:#[0-9]+]]

#pragma weak xxx = __xxx
__attribute((pure,noinline,const)) void __xxx(void) { }
// CHECK: void @__xxx() [[RN:#[0-9]+]]
__attribute((noinline,const)) int __xxx(void) { return 0; }
// CHECK: i32 @__xxx() [[RN:#[0-9]+]]

///////////// PR28611: Try multiple aliases of same undeclared symbol or alias
#pragma weak undecfunc_alias1 = undecfunc
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Driver/linker-wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// REQUIRES: nvptx-registered-target
// REQUIRES: amdgpu-registered-target

// UNSUPPORTED: system-linux
// REQUIRES: system-linux

// An externally visible variable so static libraries extract.
__attribute__((visibility("protected"), used)) int x;
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Import/attr/Inputs/S.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
extern void f() __attribute__((const));
extern char f() __attribute__((const));

struct S {
struct {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Import/attr/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
// CHECK-NEXT: LoopHintAttr
// CHECK-SAME: line:10:9

extern void f() __attribute__((const));
extern char f() __attribute__((const));

struct S;

void stmt();

void expr() {
f();
(void)f();
struct S s;
}
Loading

0 comments on commit b04df36

Please sign in to comment.