12 changes: 8 additions & 4 deletions clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -942,11 +942,15 @@ bool LoopConvertCheck::isConvertible(ASTContext *Context,
CanonicalInitVarType->isPointerType()) {
// If the initializer and the variable are both pointers check if the
// un-qualified pointee types match, otherwise we don't use auto.
if (!Context->hasSameUnqualifiedType(
CanonicalBeginType->getPointeeType(),
CanonicalInitVarType->getPointeeType()))
return false;
return Context->hasSameUnqualifiedType(
CanonicalBeginType->getPointeeType(),
CanonicalInitVarType->getPointeeType());
}

if (CanonicalBeginType->isBuiltinType() ||
CanonicalInitVarType->isBuiltinType())
return false;

} else if (FixerKind == LFK_PseudoArray) {
if (const auto *EndCall = Nodes.getNodeAs<CXXMemberCallExpr>(EndCallName)) {
// This call is required to obtain the container.
Expand Down
7 changes: 3 additions & 4 deletions clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
return false;
};
switch (New->getInitializationStyle()) {
case CXXNewInitializationStyle::None:
case CXXNewInitializationStyle::Implicit: {
case CXXNewInitializationStyle::None: {
if (ArraySizeExpr.empty()) {
Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
} else {
Expand All @@ -335,7 +334,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
}
break;
}
case CXXNewInitializationStyle::Call: {
case CXXNewInitializationStyle::Parens: {
// FIXME: Add fixes for constructors with parameters that can be created
// with a C++11 braced-init-list (e.g. std::vector, std::map).
// Unlike ordinal cases, braced list can not be deduced in
Expand Down Expand Up @@ -372,7 +371,7 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
}
break;
}
case CXXNewInitializationStyle::List: {
case CXXNewInitializationStyle::Braces: {
// Range of the substring that we do not want to remove.
SourceRange InitRange;
if (const auto *NewConstruct = New->getConstructExpr()) {
Expand Down
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
2 changes: 2 additions & 0 deletions clang-tools-extra/clang-tidy/readability/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ add_clang_library(clangTidyReadabilityModule
IdentifierLengthCheck.cpp
IdentifierNamingCheck.cpp
ImplicitBoolConversionCheck.cpp
RedundantInlineSpecifierCheck.cpp
InconsistentDeclarationParameterNameCheck.cpp
IsolateDeclarationCheck.cpp
MagicNumbersCheck.cpp
Expand All @@ -35,6 +36,7 @@ add_clang_library(clangTidyReadabilityModule
QualifiedAutoCheck.cpp
ReadabilityTidyModule.cpp
RedundantAccessSpecifiersCheck.cpp
RedundantCastingCheck.cpp
RedundantControlFlowCheck.cpp
RedundantDeclarationCheck.cpp
RedundantFunctionPtrDereferenceCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@
#include "OperatorsRepresentationCheck.h"
#include "QualifiedAutoCheck.h"
#include "RedundantAccessSpecifiersCheck.h"
#include "RedundantCastingCheck.h"
#include "RedundantControlFlowCheck.h"
#include "RedundantDeclarationCheck.h"
#include "RedundantFunctionPtrDereferenceCheck.h"
#include "RedundantInlineSpecifierCheck.h"
#include "RedundantMemberInitCheck.h"
#include "RedundantPreprocessorCheck.h"
#include "RedundantSmartptrGetCheck.h"
Expand Down Expand Up @@ -99,6 +101,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-identifier-naming");
CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
"readability-implicit-bool-conversion");
CheckFactories.registerCheck<RedundantInlineSpecifierCheck>(
"readability-redundant-inline-specifier");
CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
"readability-inconsistent-declaration-parameter-name");
CheckFactories.registerCheck<IsolateDeclarationCheck>(
Expand All @@ -117,6 +121,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-qualified-auto");
CheckFactories.registerCheck<RedundantAccessSpecifiersCheck>(
"readability-redundant-access-specifiers");
CheckFactories.registerCheck<RedundantCastingCheck>(
"readability-redundant-casting");
CheckFactories.registerCheck<RedundantFunctionPtrDereferenceCheck>(
"readability-redundant-function-ptr-dereference");
CheckFactories.registerCheck<RedundantMemberInitCheck>(
Expand Down
252 changes: 252 additions & 0 deletions clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
//===--- RedundantCastingCheck.cpp - clang-tidy ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "RedundantCastingCheck.h"
#include "../utils/FixItHintUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"

using namespace clang::ast_matchers;

namespace clang::tidy::readability {

static bool areTypesEqual(QualType S, QualType D) {
if (S == D)
return true;

const auto *TS = S->getAs<TypedefType>();
const auto *TD = D->getAs<TypedefType>();
if (TS != TD)
return false;

QualType PtrS = S->getPointeeType();
QualType PtrD = D->getPointeeType();

if (!PtrS.isNull() && !PtrD.isNull())
return areTypesEqual(PtrS, PtrD);

const DeducedType *DT = S->getContainedDeducedType();
if (DT && DT->isDeduced())
return D == DT->getDeducedType();

return false;
}

static bool areTypesEqual(QualType TypeS, QualType TypeD,
bool IgnoreTypeAliases) {
const QualType CTypeS = TypeS.getCanonicalType();
const QualType CTypeD = TypeD.getCanonicalType();
if (CTypeS != CTypeD)
return false;

return IgnoreTypeAliases || areTypesEqual(TypeS.getLocalUnqualifiedType(),
TypeD.getLocalUnqualifiedType());
}

static bool areBinaryOperatorOperandsTypesEqualToOperatorResultType(
const Expr *E, bool IgnoreTypeAliases) {
if (!E)
return true;
const Expr *WithoutImplicitAndParen = E->IgnoreParenImpCasts();
if (!WithoutImplicitAndParen)
return true;
if (const auto *B = dyn_cast<BinaryOperator>(WithoutImplicitAndParen)) {
const QualType Type = WithoutImplicitAndParen->getType();
if (Type.isNull())
return true;

const QualType NonReferenceType = Type.getNonReferenceType();
const QualType LHSType = B->getLHS()->IgnoreImplicit()->getType();
if (LHSType.isNull() || !areTypesEqual(LHSType.getNonReferenceType(),
NonReferenceType, IgnoreTypeAliases))
return false;
const QualType RHSType = B->getRHS()->IgnoreImplicit()->getType();
if (RHSType.isNull() || !areTypesEqual(RHSType.getNonReferenceType(),
NonReferenceType, IgnoreTypeAliases))
return false;
}
return true;
}

static const Decl *getSourceExprDecl(const Expr *SourceExpr) {
const Expr *CleanSourceExpr = SourceExpr->IgnoreParenImpCasts();
if (const auto *E = dyn_cast<DeclRefExpr>(CleanSourceExpr)) {
return E->getDecl();
}

if (const auto *E = dyn_cast<CallExpr>(CleanSourceExpr)) {
return E->getCalleeDecl();
}

if (const auto *E = dyn_cast<MemberExpr>(CleanSourceExpr)) {
return E->getMemberDecl();
}
return nullptr;
}

RedundantCastingCheck::RedundantCastingCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
IgnoreMacros(Options.getLocalOrGlobal("IgnoreMacros", true)),
IgnoreTypeAliases(Options.getLocalOrGlobal("IgnoreTypeAliases", false)) {}

void RedundantCastingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoreMacros", IgnoreMacros);
Options.store(Opts, "IgnoreTypeAliases", IgnoreTypeAliases);
}

void RedundantCastingCheck::registerMatchers(MatchFinder *Finder) {
auto SimpleType = qualType(hasCanonicalType(
qualType(anyOf(builtinType(), references(builtinType()),
references(pointsTo(qualType())), pointsTo(qualType())))));

auto BitfieldMemberExpr = memberExpr(member(fieldDecl(isBitField())));

Finder->addMatcher(
explicitCastExpr(
unless(hasCastKind(CK_ConstructorConversion)),
unless(hasCastKind(CK_UserDefinedConversion)),
unless(cxxFunctionalCastExpr(hasDestinationType(unless(SimpleType)))),

hasDestinationType(qualType().bind("dstType")),
hasSourceExpression(anyOf(
expr(unless(initListExpr()), unless(BitfieldMemberExpr),
hasType(qualType().bind("srcType")))
.bind("source"),
initListExpr(unless(hasInit(1, expr())),
hasInit(0, expr(unless(BitfieldMemberExpr),
hasType(qualType().bind("srcType")))
.bind("source"))))))
.bind("cast"),
this);
}

void RedundantCastingCheck::check(const MatchFinder::MatchResult &Result) {
const auto *SourceExpr = Result.Nodes.getNodeAs<Expr>("source");
auto TypeD = *Result.Nodes.getNodeAs<QualType>("dstType");

if (SourceExpr->getValueKind() == VK_LValue &&
TypeD.getCanonicalType()->isRValueReferenceType())
return;

const auto TypeS =
Result.Nodes.getNodeAs<QualType>("srcType")->getNonReferenceType();
TypeD = TypeD.getNonReferenceType();

if (!areTypesEqual(TypeS, TypeD, IgnoreTypeAliases))
return;

if (!areBinaryOperatorOperandsTypesEqualToOperatorResultType(
SourceExpr, IgnoreTypeAliases))
return;

const auto *CastExpr = Result.Nodes.getNodeAs<ExplicitCastExpr>("cast");
if (IgnoreMacros &&
(CastExpr->getBeginLoc().isMacroID() ||
CastExpr->getEndLoc().isMacroID() || CastExpr->getExprLoc().isMacroID()))
return;

{
auto Diag = diag(CastExpr->getExprLoc(),
"redundant explicit casting to the same type %0 as the "
"sub-expression, remove this casting");
Diag << TypeD;

const SourceManager &SM = *Result.SourceManager;
const SourceLocation SourceExprBegin =
SM.getExpansionLoc(SourceExpr->getBeginLoc());
const SourceLocation SourceExprEnd =
SM.getExpansionLoc(SourceExpr->getEndLoc());

if (SourceExprBegin != CastExpr->getBeginLoc())
Diag << FixItHint::CreateRemoval(SourceRange(
CastExpr->getBeginLoc(), SourceExprBegin.getLocWithOffset(-1)));

const SourceLocation NextToken = Lexer::getLocForEndOfToken(
SourceExprEnd, 0U, SM, Result.Context->getLangOpts());

if (SourceExprEnd != CastExpr->getEndLoc()) {
Diag << FixItHint::CreateRemoval(
SourceRange(NextToken, CastExpr->getEndLoc()));
}

if (utils::fixit::areParensNeededForStatement(*SourceExpr)) {
Diag << FixItHint::CreateInsertion(SourceExprBegin, "(")
<< FixItHint::CreateInsertion(NextToken, ")");
}
}

const auto *SourceExprDecl = getSourceExprDecl(SourceExpr);
if (!SourceExprDecl)
return;

if (const auto *D = dyn_cast<CXXConstructorDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from the invocation of this constructor",
DiagnosticIDs::Note);
return;
}

if (const auto *D = dyn_cast<FunctionDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from the invocation of this "
"%select{function|method}0",
DiagnosticIDs::Note)
<< isa<CXXMethodDecl>(D) << D->getReturnTypeSourceRange();
return;
}

if (const auto *D = dyn_cast<FieldDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from referencing this member",
DiagnosticIDs::Note)
<< SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
return;
}

if (const auto *D = dyn_cast<ParmVarDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from referencing this parameter",
DiagnosticIDs::Note)
<< SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
return;
}

if (const auto *D = dyn_cast<VarDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from referencing this variable",
DiagnosticIDs::Note)
<< SourceRange(D->getTypeSpecStartLoc(), D->getTypeSpecEndLoc());
return;
}

if (const auto *D = dyn_cast<EnumConstantDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from referencing this enum constant",
DiagnosticIDs::Note);
return;
}

if (const auto *D = dyn_cast<BindingDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from referencing this bound variable",
DiagnosticIDs::Note);
return;
}

if (const auto *D = dyn_cast<NonTypeTemplateParmDecl>(SourceExprDecl)) {
diag(D->getLocation(),
"source type originates from referencing this non-type template "
"parameter",
DiagnosticIDs::Note);
return;
}
}

} // namespace clang::tidy::readability
38 changes: 38 additions & 0 deletions clang-tools-extra/clang-tidy/readability/RedundantCastingCheck.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//===--- RedundantCastingCheck.h - clang-tidy -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCASTINGCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCASTINGCHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::readability {

/// Detects explicit type casting operations that involve the same source and
/// destination types, and subsequently recommend their removal.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-casting.html
class RedundantCastingCheck : public ClangTidyCheck {
public:
RedundantCastingCheck(StringRef Name, ClangTidyContext *Context);
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}

private:
const bool IgnoreMacros;
const bool IgnoreTypeAliases;
};

} // namespace clang::tidy::readability

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTCASTINGCHECK_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//===--- RedundantInlineSpecifierCheck.cpp - clang-tidy--------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "RedundantInlineSpecifierCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Token.h"

#include "../utils/LexerUtils.h"

using namespace clang::ast_matchers;

namespace clang::tidy::readability {

namespace {
AST_POLYMORPHIC_MATCHER(isInlineSpecified,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
VarDecl)) {
if (const auto *FD = dyn_cast<FunctionDecl>(&Node))
return FD->isInlineSpecified();
if (const auto *VD = dyn_cast<VarDecl>(&Node))
return VD->isInlineSpecified();
llvm_unreachable("Not a valid polymorphic type");
}

AST_POLYMORPHIC_MATCHER_P(isInternalLinkage,
AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
VarDecl),
bool, strictMode) {
if (!strictMode)
return false;
if (const auto *FD = dyn_cast<FunctionDecl>(&Node))
return FD->getStorageClass() == SC_Static || FD->isInAnonymousNamespace();
if (const auto *VD = dyn_cast<VarDecl>(&Node))
return VD->isInAnonymousNamespace();
llvm_unreachable("Not a valid polymorphic type");
}
} // namespace

static SourceLocation getInlineTokenLocation(SourceRange RangeLocation,
const SourceManager &Sources,
const LangOptions &LangOpts) {
SourceLocation Loc = RangeLocation.getBegin();
if (Loc.isMacroID())
return {};

Token FirstToken;
Lexer::getRawToken(Loc, FirstToken, Sources, LangOpts, true);
std::optional<Token> CurrentToken = FirstToken;
while (CurrentToken && CurrentToken->getLocation() < RangeLocation.getEnd() &&
CurrentToken->isNot(tok::eof)) {
if (CurrentToken->is(tok::raw_identifier) &&
CurrentToken->getRawIdentifier() == "inline")
return CurrentToken->getLocation();

CurrentToken =
Lexer::findNextToken(CurrentToken->getLocation(), Sources, LangOpts);
}
return {};
}

void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
functionDecl(isInlineSpecified(),
anyOf(isConstexpr(), isDeleted(), isDefaulted(),
isInternalLinkage(StrictMode),
allOf(isDefinition(), hasAncestor(recordDecl()))))
.bind("fun_decl"),
this);

if (StrictMode)
Finder->addMatcher(
functionTemplateDecl(
has(functionDecl(allOf(isInlineSpecified(), isDefinition()))))
.bind("templ_decl"),
this);

if (getLangOpts().CPlusPlus17) {
Finder->addMatcher(
varDecl(isInlineSpecified(),
anyOf(isInternalLinkage(StrictMode),
allOf(isConstexpr(), hasAncestor(recordDecl()))))
.bind("var_decl"),
this);
}
}

template <typename T>
void RedundantInlineSpecifierCheck::handleMatchedDecl(
const T *MatchedDecl, const SourceManager &Sources,
const MatchFinder::MatchResult &Result, StringRef Message) {
SourceLocation Loc = getInlineTokenLocation(
MatchedDecl->getSourceRange(), Sources, Result.Context->getLangOpts());
if (Loc.isValid())
diag(Loc, Message) << MatchedDecl << FixItHint::CreateRemoval(Loc);
}

void RedundantInlineSpecifierCheck::check(
const MatchFinder::MatchResult &Result) {
const SourceManager &Sources = *Result.SourceManager;

if (const auto *MatchedDecl =
Result.Nodes.getNodeAs<FunctionDecl>("fun_decl")) {
handleMatchedDecl(
MatchedDecl, Sources, Result,
"function %0 has inline specifier but is implicitly inlined");
} else if (const auto *MatchedDecl =
Result.Nodes.getNodeAs<VarDecl>("var_decl")) {
handleMatchedDecl(
MatchedDecl, Sources, Result,
"variable %0 has inline specifier but is implicitly inlined");
} else if (const auto *MatchedDecl =
Result.Nodes.getNodeAs<FunctionTemplateDecl>("templ_decl")) {
handleMatchedDecl(
MatchedDecl, Sources, Result,
"function %0 has inline specifier but is implicitly inlined");
}
}

} // namespace clang::tidy::readability
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===--- RedundantInlineSpecifierCheck.h - clang-tidy ------------*-C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTINLINESPECIFIERCHECK_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTINLINESPECIFIERCHECK_H

#include "../ClangTidyCheck.h"

namespace clang::tidy::readability {

/// Detects redundant ``inline`` specifiers on function and variable
/// declarations.
///
/// For the user-facing documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-inline-specifier.html
class RedundantInlineSpecifierCheck : public ClangTidyCheck {
public:
RedundantInlineSpecifierCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
StrictMode(Options.getLocalOrGlobal("StrictMode", false)) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
std::optional<TraversalKind> getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}

private:
template <typename T>
void handleMatchedDecl(const T *MatchedDecl, const SourceManager &Sources,
const ast_matchers::MatchFinder::MatchResult &Result,
StringRef Message);
const bool StrictMode;
};

} // namespace clang::tidy::readability

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTINLINESPECIFIERCHECK_H
1 change: 1 addition & 0 deletions clang-tools-extra/clang-tidy/utils/FixItHintUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ std::string formatDereference(const Expr &ExprNode, const ASTContext &Context);
// \brief Checks whatever a expression require extra () to be always used in
// safe way in any other expression.
bool areParensNeededForStatement(const Stmt &Node);

} // namespace clang::tidy::utils::fixit

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_FIXITHINTUTILS_H
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/DumpAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class DumpVisitor : public RecursiveASTVisitor<DumpVisitor> {
TEMPLATE_ARGUMENT_KIND(Declaration);
TEMPLATE_ARGUMENT_KIND(Template);
TEMPLATE_ARGUMENT_KIND(TemplateExpansion);
TEMPLATE_ARGUMENT_KIND(StructuralValue);
#undef TEMPLATE_ARGUMENT_KIND
}
llvm_unreachable("Unhandled ArgKind enum");
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/FindTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ class ExplicitReferenceCollector
case TemplateArgument::Pack:
case TemplateArgument::Type:
case TemplateArgument::Expression:
case TemplateArgument::StructuralValue:
break; // Handled by VisitType and VisitExpression.
};
return RecursiveASTVisitor::TraverseTemplateArgumentLoc(A);
Expand Down
33 changes: 30 additions & 3 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ New checks

Detects unsafe or redundant two-step casting operations involving ``void*``.

- New :doc:`bugprone-chained-comparison
<clang-tidy/checks/bugprone/chained-comparison>` check.

Check detects chained comparison operators that can lead to unintended
behavior or logical errors.

- New :doc:`bugprone-compare-pointer-to-member-virtual-function
<clang-tidy/checks/bugprone/compare-pointer-to-member-virtual-function>` check.

Expand Down Expand Up @@ -235,6 +241,17 @@ New checks
Finds return statements with ``void`` values used within functions with
``void`` result types.

- New :doc:`readability-redundant-casting
<clang-tidy/checks/readability/redundant-casting>` check.

Detects explicit type casting operations that involve the same source and
destination types, and subsequently recommend their removal.

- New :doc:`readability-redundant-inline-specifier
<clang-tidy/checks/readability/redundant-inline-specifier>` check.

Detects redundant ``inline`` specifiers on function and variable declarations.

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

Expand Down Expand Up @@ -326,7 +343,8 @@ Changes in existing checks
- Improved :doc:`cppcoreguidelines-prefer-member-initializer
<clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>` check to
ignore delegate constructors and ignore re-assignment for reference or when
initialization depend on field that is initialized before.
initialization depend on field that is initialized before. Additionally, it
now provides valid fixes for member variables initialized with macros.

- Improved :doc:`cppcoreguidelines-pro-bounds-array-to-pointer-decay
<clang-tidy/checks/cppcoreguidelines/pro-bounds-array-to-pointer-decay>` check
Expand Down Expand Up @@ -359,6 +377,10 @@ Changes in existing checks
to ignore unused parameters when they are marked as unused and parameters of
deleted functions and constructors.

- Improved :doc:`google-readability-casting
<clang-tidy/checks/google/readability-casting>` check to ignore constructor
calls disguised as functional casts.

- Improved :doc:`llvm-namespace-comment
<clang-tidy/checks/llvm/namespace-comment>` check to provide fixes for
``inline`` namespaces in the same format as :program:`clang-format`.
Expand Down Expand Up @@ -410,7 +432,8 @@ Changes in existing checks
- Improved :doc:`modernize-loop-convert
<clang-tidy/checks/modernize/loop-convert>` to support for-loops with
iterators initialized by free functions like ``begin``, ``end``, or ``size``
and avoid crash for array of dependent array.
and avoid crash for array of dependent array and non-dereferenceable builtin
types used as iterators.

- Improved :doc:`modernize-make-shared
<clang-tidy/checks/modernize/make-shared>` check to support
Expand All @@ -422,6 +445,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 Expand Up @@ -502,7 +529,7 @@ Changes in existing checks
<clang-tidy/checks/readability/implicit-bool-conversion>` check to take
do-while loops into account for the `AllowIntegerConditions` and
`AllowPointerConditions` options. It also now provides more consistent
suggestions when parentheses are added to the return value or expressions.
suggestions when parentheses are added to the return value or expressions.
It also ignores false-positives for comparison containing bool bitfield.

- Improved :doc:`readability-misleading-indentation
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.. title:: clang-tidy - bugprone-chained-comparison

bugprone-chained-comparison
===========================

Check detects chained comparison operators that can lead to unintended
behavior or logical errors.

Chained comparisons are expressions that use multiple comparison operators
to compare three or more values. For example, the expression ``a < b < c``
compares the values of ``a``, ``b``, and ``c``. However, this expression does
not evaluate as ``(a < b) && (b < c)``, which is probably what the developer
intended. Instead, it evaluates as ``(a < b) < c``, which may produce
unintended results, especially when the types of ``a``, ``b``, and ``c`` are
different.

To avoid such errors, the check will issue a warning when a chained
comparison operator is detected, suggesting to use parentheses to specify
the order of evaluation or to use a logical operator to separate comparison
expressions.

Consider the following examples:

.. code-block:: c++

int a = 2, b = 6, c = 4;
if (a < b < c) {
// This block will be executed
}


In this example, the developer intended to check if ``a`` is less than ``b``
and ``b`` is less than ``c``. However, the expression ``a < b < c`` is
equivalent to ``(a < b) < c``. Since ``a < b`` is ``true``, the expression
``(a < b) < c`` is evaluated as ``1 < c``, which is equivalent to ``true < c``
and is invalid in this case as ``b < c`` is ``false``.

Even that above issue could be detected as comparison of ``int`` to ``bool``,
there is more dangerous example:

.. code-block:: c++

bool a = false, b = false, c = true;
if (a == b == c) {
// This block will be executed
}

In this example, the developer intended to check if ``a``, ``b``, and ``c`` are
all equal. However, the expression ``a == b == c`` is evaluated as
``(a == b) == c``. Since ``a == b`` is true, the expression ``(a == b) == c``
is evaluated as ``true == c``, which is equivalent to ``true == true``.
This comparison yields ``true``, even though ``a`` and ``b`` are ``false``, and
are not equal to ``c``.

To avoid this issue, the developer can use a logical operator to separate the
comparison expressions, like this:

.. code-block:: c++

if (a == b && b == c) {
// This block will not be executed
}


Alternatively, use of parentheses in the comparison expressions can make the
developer's intention more explicit and help avoid misunderstanding.

.. code-block:: c++

if ((a == b) == c) {
// This block will be executed
}

3 changes: 3 additions & 0 deletions clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Clang-Tidy Checks
:doc:`bugprone-bool-pointer-implicit-conversion <bugprone/bool-pointer-implicit-conversion>`, "Yes"
:doc:`bugprone-branch-clone <bugprone/branch-clone>`,
:doc:`bugprone-casting-through-void <bugprone/casting-through-void>`,
:doc:`bugprone-chained-comparison <bugprone/chained-comparison>`,
:doc:`bugprone-compare-pointer-to-member-virtual-function <bugprone/compare-pointer-to-member-virtual-function>`,
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
Expand Down Expand Up @@ -354,6 +355,7 @@ Clang-Tidy Checks
:doc:`readability-identifier-length <readability/identifier-length>`,
:doc:`readability-identifier-naming <readability/identifier-naming>`, "Yes"
:doc:`readability-implicit-bool-conversion <readability/implicit-bool-conversion>`, "Yes"
:doc:`readability-redundant-inline-specifier <readability/redundant-inline-specifier>`, "Yes"
:doc:`readability-inconsistent-declaration-parameter-name <readability/inconsistent-declaration-parameter-name>`, "Yes"
:doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes"
:doc:`readability-magic-numbers <readability/magic-numbers>`,
Expand All @@ -365,6 +367,7 @@ Clang-Tidy Checks
:doc:`readability-operators-representation <readability/operators-representation>`, "Yes"
:doc:`readability-qualified-auto <readability/qualified-auto>`, "Yes"
:doc:`readability-redundant-access-specifiers <readability/redundant-access-specifiers>`, "Yes"
:doc:`readability-redundant-casting <readability/redundant-casting>`, "Yes"
:doc:`readability-redundant-control-flow <readability/redundant-control-flow>`, "Yes"
:doc:`readability-redundant-declaration <readability/redundant-declaration>`, "Yes"
:doc:`readability-redundant-function-ptr-dereference <readability/redundant-function-ptr-dereference>`, "Yes"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.. title:: clang-tidy - readability-redundant-casting

readability-redundant-casting
=============================

Detects explicit type casting operations that involve the same source and
destination types, and subsequently recommend their removal. Covers a range of
explicit casting operations, including ``static_cast``, ``const_cast``, C-style
casts, and ``reinterpret_cast``. Its primary objective is to enhance code
readability and maintainability by eliminating unnecessary type casting.

.. code-block:: c++

int value = 42;
int result = static_cast<int>(value);

In this example, the ``static_cast<int>(value)`` is redundant, as it performs
a cast from an ``int`` to another ``int``.

Casting operations involving constructor conversions, user-defined conversions,
functional casts, type-dependent casts, casts between distinct type aliases that
refer to the same underlying type, as well as bitfield-related casts and casts
directly from lvalue to rvalue, are all disregarded by the check.

Options
-------

.. option:: IgnoreMacros

If set to `true`, the check will not give warnings inside macros. Default
is `true`.

.. option:: IgnoreTypeAliases

When set to `false`, the check will consider type aliases, and when set to
`true`, it will resolve all type aliases and operate on the underlying
types. Default is `false`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.. title:: clang-tidy - readability-redundant-inline-specifier

readability-redundant-inline-specifier
======================================

Detects redundant ``inline`` specifiers on function and variable declarations.

Examples:

.. code-block:: c++

constexpr inline void f() {}

In the example above the keyword ``inline`` is redundant since constexpr
functions are implicitly inlined

.. code-block:: c++

class MyClass {
inline void myMethod() {}
};

In the example above the keyword ``inline`` is redundant since member functions
defined entirely inside a class/struct/union definition are implicitly inlined.

Options
-------

.. option:: StrictMode

If set to `true`, the check will also flag functions and variables that
already have internal linkage as redundant.
4 changes: 4 additions & 0 deletions clang-tools-extra/include-cleaner/test/tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ int x = foo();
// IGNORE2-NOT: - "foobar.h"
// IGNORE2: + "foo.h"

// RUN: clang-include-cleaner -print=changes %s --only-headers="foo\.h" -- -I%S/Inputs/ | FileCheck --match-full-lines --allow-empty --check-prefix=ONLY %s
// ONLY-NOT: - "foobar.h"
// ONLY: + "foo.h"

// RUN: clang-include-cleaner -print %s -- -I%S/Inputs/ | FileCheck --match-full-lines --check-prefix=PRINT %s
// PRINT: #include "foo.h"
// PRINT-NOT: {{^}}#include "foobar.h"{{$}}
Expand Down
30 changes: 27 additions & 3 deletions clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ cl::opt<std::string> HTMLReportPath{
cl::cat(IncludeCleaner),
};

cl::opt<std::string> OnlyHeaders{
"only-headers",
cl::desc("A comma-separated list of regexes to match against suffix of a "
"header. Only headers that match will be analyzed."),
cl::init(""),
cl::cat(IncludeCleaner),
};

cl::opt<std::string> IgnoreHeaders{
"ignore-headers",
cl::desc("A comma-separated list of regexes to match against suffix of a "
Expand Down Expand Up @@ -221,11 +229,12 @@ class ActionFactory : public tooling::FrontendActionFactory {
llvm::StringMap<std::string> EditedFiles;
};

std::function<bool(llvm::StringRef)> headerFilter() {
// Compiles a regex list into a function that return true if any match a header.
// Prints and returns nullptr if any regexes are invalid.
std::function<bool(llvm::StringRef)> matchesAny(llvm::StringRef RegexFlag) {
auto FilterRegs = std::make_shared<std::vector<llvm::Regex>>();

llvm::SmallVector<llvm::StringRef> Headers;
llvm::StringRef(IgnoreHeaders).split(Headers, ',', -1, /*KeepEmpty=*/false);
RegexFlag.split(Headers, ',', -1, /*KeepEmpty=*/false);
for (auto HeaderPattern : Headers) {
std::string AnchoredPattern = "(" + HeaderPattern.str() + ")$";
llvm::Regex CompiledRegex(AnchoredPattern);
Expand All @@ -246,6 +255,21 @@ std::function<bool(llvm::StringRef)> headerFilter() {
};
}

std::function<bool(llvm::StringRef)> headerFilter() {
auto OnlyMatches = matchesAny(OnlyHeaders);
auto IgnoreMatches = matchesAny(IgnoreHeaders);
if (!OnlyMatches || !IgnoreMatches)
return nullptr;

return [OnlyMatches, IgnoreMatches](llvm::StringRef Header) {
if (OnlyHeaders.getNumOccurrences() && !OnlyMatches(Header))
return true;
if (IgnoreHeaders.getNumOccurrences() && IgnoreMatches(Header))
return true;
return false;
};
}

} // namespace
} // namespace include_cleaner
} // namespace clang
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// RUN: %check_clang_tidy %s bugprone-chained-comparison %t

void badly_chained_1(int x, int y, int z)
{
int result = x < y < z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_2(int x, int y, int z)
{
int result = x <= y <= z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 <= v1 <= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_3(int x, int y, int z)
{
int result = x > y > z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 > v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_4(int x, int y, int z)
{
int result = x >= y >= z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 >= v1 >= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_5(int x, int y, int z)
{
int result = x == y != z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 == v1 != v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_6(int x, int y, int z)
{
int result = x != y == z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 != v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_multiple(int a, int b, int c, int d, int e, int f, int g, int h)
{
int result = a == b == c == d == e == f == g == h;
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_limit(int v[29])
{
// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7 == v8 == v9 == v10 == v11 == v12 == v13 == v14 == v15 == v16 == v17 == v18 == v19 == v20 == v21 == v22 == v23 == v24 == v25 == v26 == v27 == v28' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
int result = v[0] == v[1] == v[2] == v[3] == v[4] == v[5] == v[6] == v[7] ==
v[8] == v[9] == v[10] == v[11] == v[12] == v[13] == v[14] ==
v[15] == v[16] == v[17] == v[18] == v[19] == v[20] == v[21] ==
v[22] == v[23] == v[24] == v[25] == v[26] == v[27] == v[28];

}

void badly_chained_parens2(int x, int y, int z, int t, int a, int b)
{
int result = (x < y) < (z && t) > (a == b);
}
// CHECK-MESSAGES: :[[@LINE-2]]:18: warning: chained comparison 'v0 < v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_inner(int x, int y, int z, int t, int u)
{
int result = x && y < z < t && u;
}
// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void properly_chained_1(int x, int y, int z)
{
int result = x < y && y < z;
}

void properly_chained_2(int x, int y, int z)
{
int result = (x < y) == z;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-chained-comparison %t

void badly_chained_1(int x, int y, int z)
{
bool result = x < y < z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_2(int x, int y, int z)
{
bool result = x <= y <= z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 <= v1 <= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_3(int x, int y, int z)
{
bool result = x > y > z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 > v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_4(int x, int y, int z)
{
bool result = x >= y >= z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 >= v1 >= v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_5(int x, int y, int z)
{
bool result = x == y != z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 == v1 != v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_6(bool x, bool y, bool z)
{
bool result = x != y == z;
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 != v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_multiple(bool a, bool b, bool c, bool d, bool e, bool f, bool g, bool h)
{
bool result = a == b == c == d == e == f == g == h;
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_limit(bool v[29])
{
// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: chained comparison 'v0 == v1 == v2 == v3 == v4 == v5 == v6 == v7 == v8 == v9 == v10 == v11 == v12 == v13 == v14 == v15 == v16 == v17 == v18 == v19 == v20 == v21 == v22 == v23 == v24 == v25 == v26 == v27 == v28' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
bool result = v[0] == v[1] == v[2] == v[3] == v[4] == v[5] == v[6] == v[7] ==
v[8] == v[9] == v[10] == v[11] == v[12] == v[13] == v[14] ==
v[15] == v[16] == v[17] == v[18] == v[19] == v[20] == v[21] ==
v[22] == v[23] == v[24] == v[25] == v[26] == v[27] == v[28];

}

void badly_chained_parens2(int x, int y, int z, int t, int a, int b)
{
bool result = (x < y) < (z && t) > (a == b);
}
// CHECK-MESSAGES: :[[@LINE-2]]:19: warning: chained comparison 'v0 < v1 > v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void badly_chained_inner(int x, int y, int z, int t, int u)
{
bool result = x && y < z < t && u;
}
// CHECK-MESSAGES: :[[@LINE-2]]:24: warning: chained comparison 'v0 < v1 < v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

void properly_chained_1(int x, int y, int z)
{
bool result = x < y && y < z;
}

void properly_chained_2(int x, int y, bool z)
{
bool result = (x < y) == z;
}

struct Value {
bool operator<(const Value&) const;
};

bool operator==(bool, const Value&);

bool badWithCppOperator(Value a, Value b, Value c) {
return a < b == c;
}
// CHECK-MESSAGES: :[[@LINE-2]]:12: warning: chained comparison 'v0 < v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]

bool mixedBinaryAndCpp(Value a, Value b, bool c) {
return a < b == c;
}
// CHECK-MESSAGES: :[[@LINE-2]]:12: warning: chained comparison 'v0 < v1 == v2' may generate unintended results, use parentheses to specify order of evaluation or a logical operator to separate comparison expressions [bugprone-chained-comparison]
Original file line number Diff line number Diff line change
Expand Up @@ -586,3 +586,33 @@ struct ReassignmentAfterUnsafetyAssignment {
}
int m_i;
};

namespace PR70189 {
#define RGB(r,g,b) ((unsigned long)(((unsigned char)(r)|((unsigned short)((unsigned char)(g))<<8))|(((unsigned long)(unsigned char)(b))<<16)))
#define INVALID_HANDLE_VALUE ((void*)(unsigned long long)-1)
#define SIMPLE 12

class Foo {
public:
Foo() {
// CHECK-FIXES: Foo() : m_color(RGB(255, 128, 0)), m_handle(INVALID_HANDLE_VALUE), m_myval(SIMPLE) {
m_color = RGB(255, 128, 0);
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_color' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
// CHECK-FIXES: {{^\ *$}}
m_handle = INVALID_HANDLE_VALUE;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_handle' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
// CHECK-FIXES: {{^\ *$}}
m_myval = SIMPLE;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'm_myval' should be initialized in a member initializer of the constructor [cppcoreguidelines-prefer-member-initializer]
// CHECK-FIXES: {{^\ *$}}
}
private:
unsigned long m_color;
void* m_handle;
int m_myval;
};

#undef SIMPLE
#undef INVALID_HANDLE_VALUE
#undef RGB
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %check_clang_tidy -std=c++11-or-later %s google-readability-casting %t
// RUN: %check_clang_tidy -std=c++11-or-later %s google-readability-casting %t -- -- -fexceptions

bool g() { return false; }

Expand Down Expand Up @@ -322,17 +322,10 @@ void conversions() {
}

template <class T>
T functional_cast_template_used_by_class(float i) {
T functional_cast_template(float i) {
return T(i);
}

template <class T>
T functional_cast_template_used_by_int(float i) {
return T(i);
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C-style casts are discouraged; use static_cast
// CHECK-FIXES: return static_cast<T>(i);
}

struct S2 {
S2(float);
};
Expand All @@ -356,8 +349,8 @@ void functional_casts() {
auto s = S(str);

// Functional casts in template functions
functional_cast_template_used_by_class<S2>(x);
functional_cast_template_used_by_int<int>(x);
functional_cast_template<S2>(x);
functional_cast_template<int>(x);

// New expressions are not functional casts
auto w = new int(x);
Expand All @@ -366,4 +359,6 @@ void functional_casts() {
S2 t = T(x); // OK, constructor call
S2 u = U(x); // NOK, it's a reinterpret_cast in disguise
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C-style casts are discouraged; use static_cast/const_cast/reinterpret_cast

throw S2(5.0f);
}
Original file line number Diff line number Diff line change
Expand Up @@ -954,3 +954,16 @@ void dependenceArrayTest() {
}

} // namespace PseudoArray

namespace PR78381 {
struct blocked_range {
int begin() const;
int end() const;
};

void test() {
blocked_range r;
for (auto i = r.begin(); i!=r.end(); ++i) {
}
}
}
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 =
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// RUN: %check_clang_tidy -std=c++11-or-later %s readability-redundant-casting %t -- -- -fno-delayed-template-parsing
// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=,MACROS %s readability-redundant-casting %t -- \
// RUN: -config='{CheckOptions: { readability-redundant-casting.IgnoreMacros: false }}' \
// RUN: -- -fno-delayed-template-parsing
// RUN: %check_clang_tidy -std=c++11-or-later -check-suffix=,ALIASES %s readability-redundant-casting %t -- \
// RUN: -config='{CheckOptions: { readability-redundant-casting.IgnoreTypeAliases: true }}' \
// RUN: -- -fno-delayed-template-parsing

struct A {};
struct B : A {};
A getA();

void testRedundantStaticCasting(A& value) {
A& a1 = static_cast<A&>(value);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:36: note: source type originates from referencing this parameter
// CHECK-FIXES: {{^}} A& a1 = value;
}

void testRedundantConstCasting1(A& value) {
A& a2 = const_cast<A&>(value);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:36: note: source type originates from referencing this parameter
// CHECK-FIXES: {{^}} A& a2 = value;
}

void testRedundantConstCasting2(const A& value) {
const A& a3 = const_cast<const A&>(value);
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant explicit casting to the same type 'const A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:42: note: source type originates from referencing this parameter
// CHECK-FIXES: {{^}} const A& a3 = value;
}

void testRedundantReinterpretCasting(A& value) {
A& a4 = reinterpret_cast<A&>(value);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:41: note: source type originates from referencing this parameter
// CHECK-FIXES: {{^}} A& a4 = value;
}

void testRedundantCCasting(A& value) {
A& a5 = (A&)(value);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:31: note: source type originates from referencing this parameter
// CHECK-FIXES: {{^}} A& a5 = value;
}

void testDoubleCasting(A& value) {
A& a6 = static_cast<A&>(reinterpret_cast<A&>(value));
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-2]]:27: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-4]]:27: note: source type originates from referencing this parameter
// CHECK-FIXES: {{^}} A& a6 = value;
}

void testDiffrentTypesCast(B& value) {
A& a7 = static_cast<A&>(value);
}

void testCastingWithAuto() {
auto a = getA();
A& a8 = static_cast<A&>(a);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:8: note: source type originates from referencing this variable
// CHECK-FIXES: {{^}} A& a8 = a;
}

void testCastingWithConstAuto() {
const auto a = getA();
const A& a9 = static_cast<const A&>(a);
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: redundant explicit casting to the same type 'const A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:14: note: source type originates from referencing this variable
// CHECK-FIXES: {{^}} const A& a9 = a;
}

void testCastingWithAutoPtr(A& ptr) {
auto* a = &ptr;
A* a10 = static_cast<A*>(a);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant explicit casting to the same type 'A *' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-3]]:9: note: source type originates from referencing this variable
// CHECK-FIXES: {{^}} A* a10 = a;
}

template<typename T>
void testRedundantTemplateCasting(T& value) {
A& a = static_cast<A&>(value);
T& t = static_cast<T&>(value);
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: redundant explicit casting to the same type 'T' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-4]]:38: note: source type originates from referencing this parameter
// CHECK-FIXES: {{^}} T& t = value;
}

void testTemplate() {
A value;
testRedundantTemplateCasting(value);
}

void testValidRefConstCast() {
const auto a = getA();
A& a11 = const_cast<A&>(a);
}

void testValidPtrConstCast(const A* ptr) {
A* a12 = const_cast<A*>(ptr);
}

#define CAST(X) static_cast<int>(X)

void testMacroCasting(int value) {
int a = CAST(value);
// CHECK-MESSAGES-MACROS: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
}

#define PTR_NAME name

void testMacroCasting(A* PTR_NAME) {
A* a13 = static_cast<A*>(PTR_NAME);
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: redundant explicit casting to the same type 'A *' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES: {{^}} A* a13 = PTR_NAME;
}

struct CastBool {
operator bool() const {
return true;
}
};

void testUserOperatorCast(const CastBool& value) {
bool b = static_cast<bool>(value);
}

using TypeA = A;

void testTypedefCast(A& value) {
TypeA& a = static_cast<TypeA&>(value);
// CHECK-MESSAGES-ALIASES: :[[@LINE-1]]:14: warning: redundant explicit casting to the same type 'TypeA' (aka 'A') as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES-ALIASES: {{^}} TypeA& a = value;
}

void testTypedefCast2(TypeA& value) {
A& a = static_cast<A&>(value);
// CHECK-MESSAGES-ALIASES: :[[@LINE-1]]:10: warning: redundant explicit casting to the same type 'A' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES-ALIASES: {{^}} A& a = value;
}

void testFunctionalCastWithPrimitive(int a) {
int b = int(a);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES: {{^}} int b = a;
}

void testFunctionalCastWithInitExpr(unsigned a) {
unsigned b = ~unsigned{!a};
unsigned c = unsigned{0};
}

void testBinaryOperator(char c) {
int a = int(c - 'C');
}

struct BIT {
bool b:1;
};

template<typename ...Args>
void make(Args&& ...);

void testBinaryOperator(BIT b) {
make((bool)b.b);
}

struct Class {
using Iterator = const char*;

Iterator begin() {
return static_cast<Iterator>(first());
// CHECK-MESSAGES-ALIASES: :[[@LINE-1]]:12: warning: redundant explicit casting to the same type 'Iterator' (aka 'const char *') as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES-ALIASES: :[[@LINE+4]]:15: note: source type originates from the invocation of this method
// CHECK-FIXES-ALIASES: {{^}} return first();
}

const char* first();
};

void testAddOperation(int aa, int bb) {
int c = static_cast<int>(aa + bb) * aa;
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES: {{^}} int c = (aa + bb) * aa;
}

void testAddOperationWithParen(int a, int b) {
int c = static_cast<int>((a+b))*a;
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES: {{^}} int c = (a+b)*a;
}

void testRValueCast(int&& a) {
int&& b = static_cast<int&&>(a);
int&& c = static_cast<int&&>(10);
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-FIXES: {{^}} int&& c = 10;
}

template <int V>
void testRedundantNTTPCasting() {
int a = static_cast<int>(V);
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: redundant explicit casting to the same type 'int' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-4]]:15: note: source type originates from referencing this non-type template parameter
// CHECK-FIXES: {{^}} int a = V;
}

template <typename T, T V>
void testValidNTTPCasting() {
int a = static_cast<int>(V);
}

template <typename T, T V>
void testRedundantDependentNTTPCasting() {
T a = static_cast<T>(V);
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: redundant explicit casting to the same type 'T' as the sub-expression, remove this casting [readability-redundant-casting]
// CHECK-MESSAGES: :[[@LINE-4]]:25: note: source type originates from referencing this non-type template parameter
// CHECK-FIXES: {{^}} T a = V;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// RUN: %check_clang_tidy -std=c++17 %s readability-redundant-inline-specifier %t
// RUN: %check_clang_tidy -std=c++17 -check-suffixes=,STRICT %s readability-redundant-inline-specifier %t -- -config="{CheckOptions: {readability-redundant-inline-specifier.StrictMode: 'true'}}"

template <typename T> inline T f()
// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:23: warning: function 'f' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES-STRICT: template <typename T> T f()
{
return T{};
}

template <> inline double f<double>() = delete;
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: function 'f<double>' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: template <> double f<double>() = delete;

inline int g(float a)
{
return static_cast<int>(a - 5.F);
}

inline int g(double) = delete;
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: function 'g' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: int g(double) = delete;

class C
{
public:
inline C& operator=(const C&) = delete;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: C& operator=(const C&) = delete;

inline C(const C&) = default;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: C(const C&) = default;

constexpr inline C& operator=(int a);
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: constexpr C& operator=(int a);

inline C() {}
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: C() {}

constexpr inline C(int);
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: constexpr C(int);

inline int Get42() const { return 42; }
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: int Get42() const { return 42; }

static inline constexpr int C_STATIC = 42;
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: variable 'C_STATIC' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: static constexpr int C_STATIC = 42;

static constexpr int C_STATIC_2 = 42;
};

constexpr inline int Get42() { return 42; }
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: constexpr int Get42() { return 42; }


static constexpr inline int NAMESPACE_STATIC = 42;

inline static int fn0(int i)
// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:1: warning: function 'fn0' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES-STRICT: static int fn0(int i)
{
return i - 1;
}

static constexpr inline int fn1(int i)
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: function 'fn1' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: static constexpr int fn1(int i)
{
return i - 1;
}

namespace
{
inline int fn2(int i)
// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:5: warning: function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES-STRICT: int fn2(int i)
{
return i - 1;
}

inline constexpr int fn3(int i)
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'fn3' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: constexpr int fn3(int i)
{
return i - 1;
}

inline constexpr int MY_CONSTEXPR_VAR = 42;
// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:5: warning: variable 'MY_CONSTEXPR_VAR' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES-STRICT: constexpr int MY_CONSTEXPR_VAR = 42;
}

namespace ns
{
inline int fn4(int i)
{
return i - 1;
}

inline constexpr int fn5(int i)
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'fn5' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES: constexpr int fn5(int i)
{
return i - 1;
}
}

auto fn6 = [](){};

template <typename T> inline T fn7();

template <typename T> T fn7()
{
return T{};
}

template <typename T> T fn8();

template <typename T> inline T fn8()
// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:23: warning: function 'fn8' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES-STRICT: template <typename T> T fn8()
{
return T{};
}

#define INLINE_MACRO() inline void fn9() { }
INLINE_MACRO()

#define INLINE_KW inline
INLINE_KW void fn10() { }
5 changes: 5 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4999,6 +4999,11 @@ the configuration (without a prefix: ``Auto``).
int bar; int bar;
} // namespace b } // namespace b

.. _SkipMacroDefinitionBody:

**SkipMacroDefinitionBody** (``Boolean``) :versionbadge:`clang-format 18` :ref:`¶ <SkipMacroDefinitionBody>`
Do not format macro definition body.

.. _SortIncludes:

**SortIncludes** (``SortIncludesOptions``) :versionbadge:`clang-format 3.8` :ref:`¶ <SortIncludes>`
Expand Down
52 changes: 48 additions & 4 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@ C++ Language Changes

C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Implemented `P1907R1 <https://wg21.link/P1907R1>` which extends allowed non-type template argument
kinds with e.g. floating point values and pointers and references to subobjects.
This feature is still experimental. Accordingly, `__cpp_nontype_template_args` was not updated.

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -229,6 +232,11 @@ C++2c Feature Support

Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Implemented `CWG2137 <https://wg21.link/CWG2137>`_ which allows
list-initialization from objects of the same type.
- Implemented `CWG2311 <https://wg21.link/CWG2311>`_: given a prvalue ``e`` of object type
``T``, ``T{e}`` will try to resolve an initializer list constructor and will use it if successful (CWG2137).
Otherwise, if there is no initializer list constructor, the copy will be elided as if it was ``T(e)``.

- Implemented `CWG2598 <https://wg21.link/CWG2598>`_ and `CWG2096 <https://wg21.link/CWG2096>`_,
making unions (that have either no members or at least one literal member) literal types.
Expand Down Expand Up @@ -266,6 +274,13 @@ C23 Feature Support
previously implemented allowing a label at the end of a compound statement,
and now we've implemented allowing a label to be followed by a declaration
instead of a statement.
- Implemented
`N2940 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2940.pdf>`_ which
removes support for trigraphs in C23 and later. In earlier language modes,
trigraphs remain enabled by default in conforming modes (e.g. ``-std=c17``)
and disabled by default in GNU and Microsoft modes (e.g., ``-std=gnu17`` or
``-fms-compatibility``). If needed, you can enable trigraphs by passing
``-ftrigraphs``.

Non-comprehensive list of changes in this release
-------------------------------------------------
Expand Down Expand Up @@ -305,7 +320,7 @@ New Compiler Flags
handlers will be smaller. A throw expression of a type with a
potentially-throwing destructor will lead to an error.

* ``-fopenacc`` was added as a part of the effort to support OpenACC in clang.
* ``-fopenacc`` was added as a part of the effort to support OpenACC in Clang.

* ``-fcx-limited-range`` enables the naive mathematical formulas for complex
division and multiplication with no NaN checking of results. The default is
Expand All @@ -316,6 +331,16 @@ New Compiler Flags
division. See SMITH, R. L. Algorithm 116: Complex division. Commun. ACM 5, 8
(1962). The default is ``-fno-cx-fortran-rules``.

* ``-fvisibility-global-new-delete=<value>`` gives more freedom to users to
control how and if Clang forces a visibility for the replaceable new and
delete declarations. The option takes 4 values: ``force-hidden``,
``force-protected``, ``force-default`` and ``source``; ``force-default`` is
the default. Option values with prefix ``force-`` assign such declarations
an implicit visibility attribute with the corresponding visibility. An option
value of ``source`` implies that no implicit attribute is added. Without the
attribute the replaceable global new and delete operators behave normally
(like other functions) with respect to visibility attributes, pragmas and
options (e.g ``--fvisibility=``).

Deprecated Compiler Flags
-------------------------
Expand All @@ -332,6 +357,9 @@ Modified Compiler Flags
``rtdcall``. This new default CC only works for M68k and will use the new
``m68k_rtdcc`` CC on every functions that are not variadic. The ``-mrtd``
driver/frontend flag has the same effect when targeting M68k.
* ``-fvisibility-global-new-delete-hidden`` is now a deprecated spelling of
``-fvisibility-global-new-delete=force-hidden`` (``-fvisibility-global-new-delete=``
is new in this release).

Removed Compiler Flags
-------------------------
Expand Down Expand Up @@ -570,11 +598,12 @@ Improvements to Clang's diagnostics
- Clang now diagnoses unexpanded packs within the template argument lists of function template specializations.
- Clang now diagnoses attempts to bind a bitfield to an NTTP of a reference type as erroneous
converted constant expression and not as a reference to subobject.
- Clang now diagnoses ``auto`` and ``decltype(auto)`` in declarations of conversion function template
(`CWG1878: <https://cplusplus.github.io/CWG/issues/1878.html>`_)
- Clang now diagnoses the requirement that non-template friend declarations with requires clauses
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 Expand Up @@ -795,7 +824,7 @@ Bug Fixes in This Version
invalidation by invalid initializer Expr.
Fixes (`#30908 <https://github.com/llvm/llvm-project/issues/30908>`_)
- Clang now emits correct source location for code-coverage regions in `if constexpr`
and `if consteval` branches.
and `if consteval` branches. Untaken branches are now skipped.
Fixes (`#54419 <https://github.com/llvm/llvm-project/issues/54419>`_)
- Fix assertion failure when declaring a template friend function with
a constrained parameter in a template class that declares a class method
Expand All @@ -821,6 +850,8 @@ Bug Fixes in This Version
- Fix an issue with missing symbol definitions when the first coroutine
statement appears in a discarded ``if constexpr`` branch.
Fixes (`#78290 <https://github.com/llvm/llvm-project/issues/78290>`_)
- Fixed assertion failure with deleted overloaded unary operators.
Fixes (`#78314 <https://github.com/llvm/llvm-project/issues/78314>`_)

Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -996,6 +1027,9 @@ Bug Fixes to C++ Support
- Clang now allows parenthesized initialization of arrays in `operator new[]`.
Fixes: (`#68198 <https://github.com/llvm/llvm-project/issues/68198>`_)

- Fixes CTAD for aggregates on nested template classes. Fixes:
(`#77599 <https://github.com/llvm/llvm-project/issues/77599>`_)

- Fix crash when importing the same module with an dynamic initializer twice
in different visibility.
Fixes (`#67893 <https://github.com/llvm/llvm-project/issues/67893>`_)
Expand Down Expand Up @@ -1146,6 +1180,15 @@ Windows Support

LoongArch Support
^^^^^^^^^^^^^^^^^
- The ``model`` attribute is now supported for overriding the default code
model used to access global variables. The following values are supported:
``normal``, ``medium`` and ``extreme``.

*Example Code*:

.. code-block:: c
int var __attribute((model("extreme")));
RISC-V Support
^^^^^^^^^^^^^^
Expand Down Expand Up @@ -1229,6 +1272,7 @@ clang-format
- Add ``PenaltyBreakScopeResolution`` option.
- Add ``.clang-format-ignore`` files.
- Add ``AlignFunctionPointers`` sub-option for ``AlignConsecutiveDeclarations``.
- Add ``SkipMacroDefinitionBody`` option.

libclang
--------
Expand Down
69 changes: 63 additions & 6 deletions clang/docs/StandardCPlusPlusModules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ In case all ``-fprebuilt-module-path=<path/to/directory>``, ``-fmodule-file=<pat
takes highest precedence and ``-fmodule-file=<module-name>=<path/to/BMI>`` will take the second
highest precedence.

We need to specify all the dependent (directly and indirectly) BMIs.
See https://github.com/llvm/llvm-project/issues/62707 for detail.

When we compile a ``module implementation unit``, we must specify the BMI of the corresponding
``primary module interface unit``.
Since the language specification says a module implementation unit implicitly imports
Expand Down Expand Up @@ -689,14 +692,68 @@ the BMI within ``clang-cl.exe``.

This is tracked in: https://github.com/llvm/llvm-project/issues/64118

delayed template parsing is not supported/broken with C++ modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
false positive ODR violation diagnostic due to using inconsistent qualified but the same type
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ODR violation is a pretty common issue when using modules.
Sometimes the program violated the One Definition Rule actually.
But sometimes it shows the compiler gives false positive diagnostics.

One often reported example is:

.. code-block:: c++

// part.cc
module;
typedef long T;
namespace ns {
inline void fun() {
(void)(T)0;
}
}
export module repro:part;

// repro.cc
module;
typedef long T;
namespace ns {
using ::T;
}
namespace ns {
inline void fun() {
(void)(T)0;
}
}
export module repro;
export import :part;

Currently the compiler complains about the inconsistent definition of `fun()` in
2 module units. This is incorrect. Since both definitions of `fun()` has the same
spelling and `T` refers to the same type entity finally. So the program should be
fine.

This is tracked in https://github.com/llvm/llvm-project/issues/78850.

Using TU-local entity in other units
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Module units are translation units. So the entities which should only be local to the
module unit itself shouldn't be used by other units in any means.

In the language side, to address the idea formally, the language specification defines
the concept of ``TU-local`` and ``exposure`` in
`basic.link/p14 <https://eel.is/c++draft/basic.link#14>`_,
`basic.link/p15 <https://eel.is/c++draft/basic.link#15>`_,
`basic.link/p16 <https://eel.is/c++draft/basic.link#16>`_,
`basic.link/p17 <https://eel.is/c++draft/basic.link#17>`_ and
`basic.link/p18 <https://eel.is/c++draft/basic.link#18>`_.

The feature `-fdelayed-template-parsing` can't work well with C++ modules now.
Note that this is significant on Windows since the option will be enabled by default
on Windows.
However, the compiler doesn't support these 2 ideas formally.
This results in unclear and confusing diagnostic messages.
And it is worse that the compiler may import TU-local entities to other units without any
diagnostics.

This is tracked in: https://github.com/llvm/llvm-project/issues/61068
This is tracked in https://github.com/llvm/llvm-project/issues/78173.

Header Units
============
Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,6 @@ class ConstantExpr final
return ConstantExprBits.APValueKind != APValue::None;
}
APValue getAPValueResult() const;
APValue &getResultAsAPValue() const { return APValueResult(); }
llvm::APSInt getResultAsAPSInt() const;
// Iterators
child_range children() { return child_range(&SubExpr, &SubExpr+1); }
Expand Down
19 changes: 3 additions & 16 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -2210,14 +2210,11 @@ enum class CXXNewInitializationStyle {
/// New-expression has no initializer as written.
None,

/// New-expression has no written initializer, but has an implicit one.
Implicit,

/// New-expression has a C++98 paren-delimited initializer.
Call,
Parens,

/// New-expression has a C++11 list-initializer.
List
Braces
};

/// Represents a new-expression for memory allocation and constructor
Expand Down Expand Up @@ -2388,17 +2385,7 @@ class CXXNewExpr final
bool isGlobalNew() const { return CXXNewExprBits.IsGlobalNew; }

/// Whether this new-expression has any initializer at all.
bool hasInitializer() const {
switch (getInitializationStyle()) {
case CXXNewInitializationStyle::None:
return false;
case CXXNewInitializationStyle::Implicit:
case CXXNewInitializationStyle::Call:
case CXXNewInitializationStyle::List:
return true;
}
llvm_unreachable("Unknown initializer");
}
bool hasInitializer() const { return CXXNewExprBits.HasInitializer; }

/// The kind of initializer this new-expression has.
CXXNewInitializationStyle getInitializationStyle() const {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/ODRHash.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

namespace clang {

class APValue;
class Decl;
class IdentifierInfo;
class NestedNameSpecifier;
Expand Down Expand Up @@ -101,6 +102,8 @@ class ODRHash {
// Save booleans until the end to lower the size of data to process.
void AddBoolean(bool value);

void AddStructuralValue(const APValue &);

static bool isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent);

private:
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/AST/PropertiesBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,20 @@ let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
return TemplateArgument(ctx, value, type, isDefaulted);
}]>;
}
let Class = PropertyTypeCase<TemplateArgument, "StructuralValue"> in {
def : Property<"value", APValue> {
let Read = [{ node.getAsStructuralValue() }];
}
def : Property<"type", QualType> {
let Read = [{ node.getStructuralValueType() }];
}
def : Property<"isDefaulted", Bool> {
let Read = [{ node.getIsDefaulted() }];
}
def : Creator<[{
return TemplateArgument(ctx, type, value, isDefaulted);
}]>;
}
let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
def : Property<"name", TemplateName> {
let Read = [{ node.getAsTemplateOrTemplatePattern() }];
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
case TemplateArgument::StructuralValue:
return true;

case TemplateArgument::Type:
Expand Down Expand Up @@ -882,6 +883,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc(
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
case TemplateArgument::NullPtr:
case TemplateArgument::StructuralValue:
return true;

case TemplateArgument::Type: {
Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -868,9 +868,11 @@ class alignas(void *) Stmt {
LLVM_PREFERRED_TYPE(bool)
unsigned UsualArrayDeleteWantsSize : 1;

/// What kind of initializer do we have? Could be none, parens, or braces.
/// In storage, we distinguish between "none, and no initializer expr", and
/// "none, but an implicit initializer expr".
// Is initializer expr present?
LLVM_PREFERRED_TYPE(bool)
unsigned HasInitializer : 1;

/// What kind of initializer syntax used? Could be none, parens, or braces.
LLVM_PREFERRED_TYPE(CXXNewInitializationStyle)
unsigned StoredInitializationStyle : 2;

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/TemplateArgumentVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Base {
DISPATCH(Declaration);
DISPATCH(NullPtr);
DISPATCH(Integral);
DISPATCH(StructuralValue);
DISPATCH(Template);
DISPATCH(TemplateExpansion);
DISPATCH(Expression);
Expand All @@ -59,6 +60,7 @@ class Base {
VISIT_METHOD(Declaration);
VISIT_METHOD(NullPtr);
VISIT_METHOD(Integral);
VISIT_METHOD(StructuralValue);
VISIT_METHOD(Template);
VISIT_METHOD(TemplateExpansion);
VISIT_METHOD(Expression);
Expand Down
86 changes: 55 additions & 31 deletions clang/include/clang/AST/TemplateBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ template <> struct PointerLikeTypeTraits<clang::Expr *> {

namespace clang {

class APValue;
class ASTContext;
class Expr;
struct PrintingPolicy;
Expand Down Expand Up @@ -80,6 +81,13 @@ class TemplateArgument {
/// that was provided for an integral non-type template parameter.
Integral,

/// The template argument is a non-type template argument that can't be
/// represented by the special-case Declaration, NullPtr, or Integral
/// forms. These values are only ever produced by constant evaluation,
/// so cannot be dependent.
/// TODO: merge Declaration, NullPtr and Integral into this?
StructuralValue,

/// The template argument is a template name that was provided for a
/// template template parameter.
Template,
Expand Down Expand Up @@ -130,6 +138,14 @@ class TemplateArgument {
};
void *Type;
};
struct V {
LLVM_PREFERRED_TYPE(ArgKind)
unsigned Kind : 31;
LLVM_PREFERRED_TYPE(bool)
unsigned IsDefaulted : 1;
APValue *Value;
void *Type;
};
struct A {
LLVM_PREFERRED_TYPE(ArgKind)
unsigned Kind : 31;
Expand All @@ -156,37 +172,42 @@ class TemplateArgument {
union {
struct DA DeclArg;
struct I Integer;
struct V Value;
struct A Args;
struct TA TemplateArg;
struct TV TypeOrValue;
};

void initFromType(QualType T, bool IsNullPtr, bool IsDefaulted);
void initFromDeclaration(ValueDecl *D, QualType QT, bool IsDefaulted);
void initFromIntegral(const ASTContext &Ctx, const llvm::APSInt &Value,
QualType Type, bool IsDefaulted);
void initFromStructural(const ASTContext &Ctx, QualType Type,
const APValue &V, bool IsDefaulted);

public:
/// Construct an empty, invalid template argument.
constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}

/// Construct a template type argument.
TemplateArgument(QualType T, bool isNullPtr = false,
bool IsDefaulted = false) {
TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
TypeOrValue.IsDefaulted = IsDefaulted;
TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
initFromType(T, isNullPtr, IsDefaulted);
}

/// Construct a template argument that refers to a
/// declaration, which is either an external declaration or a
/// template declaration.
/// Construct a template argument that refers to a (non-dependent)
/// declaration.
TemplateArgument(ValueDecl *D, QualType QT, bool IsDefaulted = false) {
assert(D && "Expected decl");
DeclArg.Kind = Declaration;
DeclArg.IsDefaulted = IsDefaulted;
DeclArg.QT = QT.getAsOpaquePtr();
DeclArg.D = D;
initFromDeclaration(D, QT, IsDefaulted);
}

/// Construct an integral constant template argument. The memory to
/// store the value is allocated with Ctx.
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type,
TemplateArgument(const ASTContext &Ctx, const llvm::APSInt &Value,
QualType Type, bool IsDefaulted = false);

/// Construct a template argument from an arbitrary constant value.
TemplateArgument(const ASTContext &Ctx, QualType Type, const APValue &Value,
bool IsDefaulted = false);

/// Construct an integral constant template argument with the same
Expand Down Expand Up @@ -297,7 +318,7 @@ class TemplateArgument {
/// Retrieve the type for a type template argument.
QualType getAsType() const {
assert(getKind() == Type && "Unexpected kind");
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V));
}

/// Retrieve the declaration for a declaration non-type
Expand All @@ -315,7 +336,7 @@ class TemplateArgument {
/// Retrieve the type for null non-type template argument.
QualType getNullPtrType() const {
assert(getKind() == NullPtr && "Unexpected kind");
return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue.V));
return QualType::getFromOpaquePtr(reinterpret_cast<void *>(TypeOrValue.V));
}

/// Retrieve the template name for a template name argument.
Expand Down Expand Up @@ -371,6 +392,14 @@ class TemplateArgument {
/// default template parameter.
bool getIsDefaulted() const { return (bool)TypeOrValue.IsDefaulted; }

/// Get the value of a StructuralValue.
const APValue &getAsStructuralValue() const { return *Value.Value; }

/// Get the type of a StructuralValue.
QualType getStructuralValueType() const {
return QualType::getFromOpaquePtr(Value.Type);
}

/// If this is a non-type template argument, get its type. Otherwise,
/// returns a null QualType.
QualType getNonTypeTemplateArgumentType() const;
Expand Down Expand Up @@ -516,6 +545,7 @@ class TemplateArgumentLoc {
assert(Argument.getKind() == TemplateArgument::NullPtr ||
Argument.getKind() == TemplateArgument::Integral ||
Argument.getKind() == TemplateArgument::Declaration ||
Argument.getKind() == TemplateArgument::StructuralValue ||
Argument.getKind() == TemplateArgument::Expression);
}

Expand All @@ -541,13 +571,9 @@ class TemplateArgumentLoc {
/// - Fetches the full source range of the argument.
SourceRange getSourceRange() const LLVM_READONLY;

const TemplateArgument &getArgument() const {
return Argument;
}
const TemplateArgument &getArgument() const { return Argument; }

TemplateArgumentLocInfo getLocInfo() const {
return LocInfo;
}
TemplateArgumentLocInfo getLocInfo() const { return LocInfo; }

TypeSourceInfo *getTypeSourceInfo() const {
if (Argument.getKind() != TemplateArgument::Type)
Expand Down Expand Up @@ -575,6 +601,11 @@ class TemplateArgumentLoc {
return LocInfo.getAsExpr();
}

Expr *getSourceStructuralValueExpression() const {
assert(Argument.getKind() == TemplateArgument::StructuralValue);
return LocInfo.getAsExpr();
}

NestedNameSpecifierLoc getTemplateQualifierLoc() const {
if (Argument.getKind() != TemplateArgument::Template &&
Argument.getKind() != TemplateArgument::TemplateExpansion)
Expand Down Expand Up @@ -606,8 +637,7 @@ class TemplateArgumentListInfo {
public:
TemplateArgumentListInfo() = default;

TemplateArgumentListInfo(SourceLocation LAngleLoc,
SourceLocation RAngleLoc)
TemplateArgumentListInfo(SourceLocation LAngleLoc, SourceLocation RAngleLoc)
: LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {}

// This can leak if used in an AST node, use ASTTemplateArgumentListInfo
Expand All @@ -626,21 +656,15 @@ class TemplateArgumentListInfo {
return Arguments.data();
}

llvm::ArrayRef<TemplateArgumentLoc> arguments() const {
return Arguments;
}
llvm::ArrayRef<TemplateArgumentLoc> arguments() const { return Arguments; }

const TemplateArgumentLoc &operator[](unsigned I) const {
return Arguments[I];
}

TemplateArgumentLoc &operator[](unsigned I) {
return Arguments[I];
}
TemplateArgumentLoc &operator[](unsigned I) { return Arguments[I]; }

void addArgument(const TemplateArgumentLoc &Loc) {
Arguments.push_back(Loc);
}
void addArgument(const TemplateArgumentLoc &Loc) { Arguments.push_back(Loc); }
};

/// Represents an explicit template argument list in C++, e.g.,
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
15 changes: 9 additions & 6 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 Expand Up @@ -2411,7 +2418,8 @@ def err_auto_not_allowed : Error<
"|in type allocated by 'new'|in K&R-style function parameter"
"|in template parameter|in friend declaration|in function prototype that is "
"not a function declaration|in requires expression parameter"
"|in array declaration}1">;
"|in array declaration"
"|in declaration of conversion function template}1">;
def err_dependent_deduced_tst : Error<
"typename specifier refers to "
"%select{class template|function template|variable template|alias template|"
Expand Down Expand Up @@ -5146,8 +5154,6 @@ def err_non_type_template_arg_subobject : Error<
"non-type template argument refers to subobject '%0'">;
def err_non_type_template_arg_addr_label_diff : Error<
"template argument / label address difference / what did you expect?">;
def err_non_type_template_arg_unsupported : Error<
"non-type template argument of type %0 is not yet supported">;
def err_template_arg_not_convertible : Error<
"non-type template argument of type %0 cannot be converted to a value "
"of type %1">;
Expand Down Expand Up @@ -5199,9 +5205,6 @@ def err_template_arg_not_object_or_func : Error<
"non-type template argument does not refer to an object or function">;
def err_template_arg_not_pointer_to_member_form : Error<
"non-type template argument is not a pointer to member constant">;
def err_template_arg_member_ptr_base_derived_not_supported : Error<
"non-type template argument of pointer-to-member type %1 that refers "
"to member %q0 of a different class is not supported yet">;
def err_template_arg_invalid : Error<
"non-type template argument '%0' is invalid">;
def ext_template_arg_extra_parens : ExtWarn<
Expand Down
23 changes: 12 additions & 11 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ BENIGN_LANGOPT(IgnoreXCOFFVisibility, 1, 0, "All the visibility attributes that
BENIGN_LANGOPT(VisibilityInlinesHiddenStaticLocalVar, 1, 0,
"hidden visibility for static local variables in inline C++ "
"methods when -fvisibility-inlines hidden is enabled")
LANGOPT(GlobalAllocationFunctionVisibilityHidden , 1, 0, "hidden visibility for global operator new and delete declaration")
ENUM_LANGOPT(GlobalAllocationFunctionVisibility, VisibilityForcedKinds, 3, VisibilityForcedKinds::ForceDefault,
"How to apply visibility to global operator new and delete declarations")
LANGOPT(NewInfallible , 1, 0, "Treats throwing global C++ operator new as always returning valid memory (annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.")
BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype")
BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support")
Expand Down Expand Up @@ -359,16 +360,16 @@ BENIGN_ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility,
"default visibility for types [-ftype-visibility]")
LANGOPT(SetVisibilityForExternDecls, 1, 0,
"apply global symbol visibility to external declarations without an explicit visibility")
LANGOPT(VisibilityFromDLLStorageClass, 1, 0,
"set the visiblity of globals from their DLL storage class [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(DLLExportVisibility, Visibility, 3, DefaultVisibility,
"visibility for functions and variables with dllexport annotations [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(NoDLLStorageClassVisibility, Visibility, 3, HiddenVisibility,
"visibility for functions and variables without an explicit DLL storage class [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(ExternDeclDLLImportVisibility, Visibility, 3, DefaultVisibility,
"visibility for external declarations with dllimport annotations [-fvisibility-from-dllstorageclass]")
ENUM_LANGOPT(ExternDeclNoDLLStorageClassVisibility, Visibility, 3, HiddenVisibility,
"visibility for external declarations without an explicit DLL storage class [-fvisibility-from-dllstorageclass]")
BENIGN_LANGOPT(VisibilityFromDLLStorageClass, 1, 0,
"override the visibility of globals based on their final DLL storage class [-fvisibility-from-dllstorageclass]")
BENIGN_ENUM_LANGOPT(DLLExportVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Default,
"how to adjust the visibility for functions and variables with dllexport annotations [-fvisibility-dllexport]")
BENIGN_ENUM_LANGOPT(NoDLLStorageClassVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Hidden,
"how to adjust the visibility for functions and variables without an explicit DLL storage class [-fvisibility-nodllstorageclass]")
BENIGN_ENUM_LANGOPT(ExternDeclDLLImportVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Default,
"how to adjust the visibility for external declarations with dllimport annotations [-fvisibility-externs-dllimport]")
BENIGN_ENUM_LANGOPT(ExternDeclNoDLLStorageClassVisibility, VisibilityFromDLLStorageClassKinds, 3, VisibilityFromDLLStorageClassKinds::Hidden,
"how to adjust the visibility for external declarations without an explicit DLL storage class [-fvisibility-externs-nodllstorageclass]")
BENIGN_LANGOPT(SemanticInterposition , 1, 0, "semantic interposition")
BENIGN_LANGOPT(HalfNoSemanticInterposition, 1, 0,
"Like -fno-semantic-interposition but don't use local aliases")
Expand Down
42 changes: 42 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,28 @@ class LangOptions : public LangOptionsBase {
All,
};

enum class VisibilityForcedKinds {
/// Force hidden visibility
ForceHidden,
/// Force protected visibility
ForceProtected,
/// Force default visibility
ForceDefault,
/// Don't alter the visibility
Source,
};

enum class VisibilityFromDLLStorageClassKinds {
/// Keep the IR-gen assigned visibility.
Keep,
/// Override the IR-gen assigned visibility with default visibility.
Default,
/// Override the IR-gen assigned visibility with hidden visibility.
Hidden,
/// Override the IR-gen assigned visibility with protected visibility.
Protected,
};

enum class StrictFlexArraysLevelKind {
/// Any trailing array member is a FAM.
Default = 0,
Expand Down Expand Up @@ -662,6 +684,26 @@ class LangOptions : public LangOptionsBase {
DefaultVisiblityExportMapping::All;
}

bool hasGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() !=
VisibilityForcedKinds::Source;
}

bool hasDefaultGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() ==
VisibilityForcedKinds::ForceDefault;
}

bool hasProtectedGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() ==
VisibilityForcedKinds::ForceProtected;
}

bool hasHiddenGlobalAllocationFunctionVisibility() const {
return getGlobalAllocationFunctionVisibility() ==
VisibilityForcedKinds::ForceHidden;
}

/// Remap path prefix according to -fmacro-prefix-path option.
void remapPathPrefix(SmallVectorImpl<char> &Path) const;

Expand Down
15 changes: 12 additions & 3 deletions clang/include/clang/Basic/ObjCRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,13 @@ class ObjCRuntime {
case GCC:
return false;
case GNUstep:
return false;
// This could be enabled for all versions, except for the fact that the
// implementation of `objc_retain` and friends prior to 2.2 call [object
// retain] in their fall-back paths, which leads to infinite recursion if
// the runtime is built with this enabled. Since distributions typically
// build all Objective-C things with the same compiler version and flags,
// it's better to be conservative here.
return (getVersion() >= VersionTuple(2, 2));
case ObjFW:
return false;
}
Expand Down Expand Up @@ -248,7 +254,7 @@ class ObjCRuntime {
case GCC:
return false;
case GNUstep:
return false;
return getVersion() >= VersionTuple(2, 2);
case ObjFW:
return false;
}
Expand All @@ -266,6 +272,8 @@ class ObjCRuntime {
return getVersion() >= VersionTuple(12, 2);
case WatchOS:
return getVersion() >= VersionTuple(5, 2);
case GNUstep:
return getVersion() >= VersionTuple(2, 2);
default:
return false;
}
Expand Down Expand Up @@ -463,7 +471,8 @@ class ObjCRuntime {
case iOS: return true;
case WatchOS: return true;
case GCC: return false;
case GNUstep: return false;
case GNUstep:
return (getVersion() >= VersionTuple(2, 2));
case ObjFW: return false;
}
llvm_unreachable("bad kind");
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ enum class OpenACCClauseKind {
Collapse,
/// 'bind' clause, allowed on routine constructs.
Bind,
/// 'vector_length' clause, allowed on 'parallel', 'kernels', 'parallel loop',
/// and 'kernels loop' constructs.
VectorLength,

/// Represents an invalid clause, for the purposes of parsing.
Invalid,
Expand Down Expand Up @@ -322,6 +325,9 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
case OpenACCClauseKind::Bind:
return Out << "bind";

case OpenACCClauseKind::VectorLength:
return Out << "vector_length";

case OpenACCClauseKind::Invalid:
return Out << "<invalid>";
}
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/TargetBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,9 @@ namespace clang {
bool isZExtReturn() const { return Flags & IsZExtReturn; }
bool isByteIndexed() const { return Flags & IsByteIndexed; }
bool isOverloadNone() const { return Flags & IsOverloadNone; }
bool isOverloadWhile() const { return Flags & IsOverloadWhile; }
bool isOverloadWhileOrMultiVecCvt() const {
return Flags & IsOverloadWhileOrMultiVecCvt;
}
bool isOverloadDefault() const { return !(Flags & OverloadKindMask); }
bool isOverloadWhileRW() const { return Flags & IsOverloadWhileRW; }
bool isOverloadCvt() const { return Flags & IsOverloadCvt; }
Expand Down
Loading