Skip to content

Commit ad1ed80

Browse files
authored
Merge branch 'main' into fix/111854
2 parents 01dc877 + 470a599 commit ad1ed80

File tree

162 files changed

+8263
-4170
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

162 files changed

+8263
-4170
lines changed

clang-tools-extra/docs/clang-tidy/checks/bugprone/unchecked-optional-access.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ For example:
7676
}
7777
}
7878
79+
Exception: accessor methods
80+
```````````````````````````
81+
82+
The check assumes *accessor* methods of a class are stable, with a heuristic to
83+
determine which methods are accessors. Specifically, parameter-free ``const``
84+
methods are treated as accessors. Note that this is not guaranteed to be safe
85+
-- but, it is widely used (safely) in practice, and so we have chosen to treat
86+
it as generally safe. Calls to non ``const`` methods are assumed to modify
87+
the state of the object and affect the stability of earlier accessor calls.
88+
7989
Rely on invariants of uncommon APIs
8090
-----------------------------------
8191

clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/ASTContext.h"
1818
#include "clang/Analysis/CFG.h"
1919
#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
20+
#include "clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h"
2021
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
2122
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
2223
#include "clang/Analysis/FlowSensitive/NoopLattice.h"
@@ -39,23 +40,28 @@ struct UncheckedOptionalAccessModelOptions {
3940
bool IgnoreSmartPointerDereference = false;
4041
};
4142

43+
using UncheckedOptionalAccessLattice = CachedConstAccessorsLattice<NoopLattice>;
44+
4245
/// Dataflow analysis that models whether optionals hold values or not.
4346
///
4447
/// Models the `std::optional`, `absl::optional`, and `base::Optional` types.
4548
class UncheckedOptionalAccessModel
46-
: public DataflowAnalysis<UncheckedOptionalAccessModel, NoopLattice> {
49+
: public DataflowAnalysis<UncheckedOptionalAccessModel,
50+
UncheckedOptionalAccessLattice> {
4751
public:
4852
UncheckedOptionalAccessModel(ASTContext &Ctx, dataflow::Environment &Env);
4953

5054
/// Returns a matcher for the optional classes covered by this model.
5155
static ast_matchers::DeclarationMatcher optionalClassDecl();
5256

53-
static NoopLattice initialElement() { return {}; }
57+
static UncheckedOptionalAccessLattice initialElement() { return {}; }
5458

55-
void transfer(const CFGElement &Elt, NoopLattice &L, Environment &Env);
59+
void transfer(const CFGElement &Elt, UncheckedOptionalAccessLattice &L,
60+
Environment &Env);
5661

5762
private:
58-
CFGMatchSwitch<TransferState<NoopLattice>> TransferMatchSwitch;
63+
CFGMatchSwitch<TransferState<UncheckedOptionalAccessLattice>>
64+
TransferMatchSwitch;
5965
};
6066

6167
class UncheckedOptionalAccessDiagnoser {
@@ -65,7 +71,8 @@ class UncheckedOptionalAccessDiagnoser {
6571

6672
llvm::SmallVector<SourceLocation>
6773
operator()(const CFGElement &Elt, ASTContext &Ctx,
68-
const TransferStateForDiagnostics<NoopLattice> &State) {
74+
const TransferStateForDiagnostics<UncheckedOptionalAccessLattice>
75+
&State) {
6976
return DiagnoseMatchSwitch(Elt, Ctx, State.Env);
7077
}
7178

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10188,7 +10188,7 @@ def warn_new_dangling_initializer_list : Warning<
1018810188
"will be destroyed at the end of the full-expression">,
1018910189
InGroup<DanglingInitializerList>;
1019010190
def warn_dangling_pointer_assignment : Warning<
10191-
"object backing the pointer %0 "
10191+
"object backing %select{|the pointer }0%1 "
1019210192
"will be destroyed at the end of the full-expression">,
1019310193
InGroup<DanglingAssignment>;
1019410194

clang/include/clang/Basic/Module.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace clang {
4848

4949
class FileManager;
5050
class LangOptions;
51+
class ModuleMap;
5152
class TargetInfo;
5253

5354
/// Describes the name of a module.
@@ -99,6 +100,15 @@ struct ASTFileSignature : std::array<uint8_t, 20> {
99100
}
100101
};
101102

103+
/// Required to construct a Module.
104+
///
105+
/// This tag type is only constructible by ModuleMap, guaranteeing it ownership
106+
/// of all Module instances.
107+
class ModuleConstructorTag {
108+
explicit ModuleConstructorTag() = default;
109+
friend ModuleMap;
110+
};
111+
102112
/// Describes a module or submodule.
103113
///
104114
/// Aligned to 8 bytes to allow for llvm::PointerIntPair<Module *, 3>.
@@ -497,8 +507,9 @@ class alignas(8) Module {
497507
std::vector<Conflict> Conflicts;
498508

499509
/// Construct a new module or submodule.
500-
Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
501-
bool IsFramework, bool IsExplicit, unsigned VisibilityID);
510+
Module(ModuleConstructorTag, StringRef Name, SourceLocation DefinitionLoc,
511+
Module *Parent, bool IsFramework, bool IsExplicit,
512+
unsigned VisibilityID);
502513

503514
~Module();
504515

@@ -749,7 +760,6 @@ class alignas(8) Module {
749760
///
750761
/// \returns The submodule if found, or NULL otherwise.
751762
Module *findSubmodule(StringRef Name) const;
752-
Module *findOrInferSubmodule(StringRef Name);
753763

754764
/// Get the Global Module Fragment (sub-module) for this module, it there is
755765
/// one.

clang/include/clang/Lex/ModuleMap.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,12 @@ class ModuleMap {
9393
/// named LangOpts::CurrentModule, if we've loaded it).
9494
Module *SourceModule = nullptr;
9595

96+
/// The allocator for all (sub)modules.
97+
llvm::SpecificBumpPtrAllocator<Module> ModulesAlloc;
98+
9699
/// Submodules of the current module that have not yet been attached to it.
97-
/// (Ownership is transferred if/when we create an enclosing module.)
98-
llvm::SmallVector<std::unique_ptr<Module>, 8> PendingSubmodules;
100+
/// (Relationship is set up if/when we create an enclosing module.)
101+
llvm::SmallVector<Module *, 8> PendingSubmodules;
99102

100103
/// The top-level modules that are known.
101104
llvm::StringMap<Module *> Modules;
@@ -502,6 +505,8 @@ class ModuleMap {
502505
/// \returns The named module, if known; otherwise, returns null.
503506
Module *findModule(StringRef Name) const;
504507

508+
Module *findOrInferSubmodule(Module *Parent, StringRef Name);
509+
505510
/// Retrieve a module with the given name using lexical name lookup,
506511
/// starting at the given context.
507512
///

clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717
#include "clang/AST/Expr.h"
1818
#include "clang/AST/ExprCXX.h"
1919
#include "clang/AST/Stmt.h"
20+
#include "clang/AST/Type.h"
2021
#include "clang/ASTMatchers/ASTMatchers.h"
2122
#include "clang/ASTMatchers/ASTMatchersMacros.h"
2223
#include "clang/Analysis/CFG.h"
2324
#include "clang/Analysis/FlowSensitive/CFGMatchSwitch.h"
2425
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
2526
#include "clang/Analysis/FlowSensitive/Formula.h"
26-
#include "clang/Analysis/FlowSensitive/NoopLattice.h"
27+
#include "clang/Analysis/FlowSensitive/RecordOps.h"
2728
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
2829
#include "clang/Analysis/FlowSensitive/Value.h"
2930
#include "clang/Basic/SourceLocation.h"
@@ -104,10 +105,17 @@ static const CXXRecordDecl *getOptionalBaseClass(const CXXRecordDecl *RD) {
104105
return nullptr;
105106
}
106107

108+
static bool isSupportedOptionalType(QualType Ty) {
109+
const CXXRecordDecl *Optional =
110+
getOptionalBaseClass(Ty->getAsCXXRecordDecl());
111+
return Optional != nullptr;
112+
}
113+
107114
namespace {
108115

109116
using namespace ::clang::ast_matchers;
110-
using LatticeTransferState = TransferState<NoopLattice>;
117+
118+
using LatticeTransferState = TransferState<UncheckedOptionalAccessLattice>;
111119

112120
AST_MATCHER(CXXRecordDecl, optionalClass) { return hasOptionalClassName(Node); }
113121

@@ -325,6 +333,19 @@ auto isValueOrNotEqX() {
325333
ComparesToSame(integerLiteral(equals(0)))));
326334
}
327335

336+
auto isZeroParamConstMemberCall() {
337+
return cxxMemberCallExpr(
338+
callee(cxxMethodDecl(parameterCountIs(0), isConst())));
339+
}
340+
341+
auto isNonConstMemberCall() {
342+
return cxxMemberCallExpr(callee(cxxMethodDecl(unless(isConst()))));
343+
}
344+
345+
auto isNonConstMemberOperatorCall() {
346+
return cxxOperatorCallExpr(callee(cxxMethodDecl(unless(isConst()))));
347+
}
348+
328349
auto isCallReturningOptional() {
329350
return callExpr(hasType(qualType(
330351
anyOf(desugarsToOptionalOrDerivedType(),
@@ -523,6 +544,99 @@ void transferCallReturningOptional(const CallExpr *E,
523544
setHasValue(*Loc, State.Env.makeAtomicBoolValue(), State.Env);
524545
}
525546

547+
void handleConstMemberCall(const CallExpr *CE,
548+
dataflow::RecordStorageLocation *RecordLoc,
549+
const MatchFinder::MatchResult &Result,
550+
LatticeTransferState &State) {
551+
// If the const method returns an optional or reference to an optional.
552+
if (RecordLoc != nullptr && isSupportedOptionalType(CE->getType())) {
553+
StorageLocation *Loc =
554+
State.Lattice.getOrCreateConstMethodReturnStorageLocation(
555+
*RecordLoc, CE, State.Env, [&](StorageLocation &Loc) {
556+
setHasValue(cast<RecordStorageLocation>(Loc),
557+
State.Env.makeAtomicBoolValue(), State.Env);
558+
});
559+
if (Loc == nullptr)
560+
return;
561+
if (CE->isGLValue()) {
562+
// If the call to the const method returns a reference to an optional,
563+
// link the call expression to the cached StorageLocation.
564+
State.Env.setStorageLocation(*CE, *Loc);
565+
} else {
566+
// If the call to the const method returns an optional by value, we
567+
// need to use CopyRecord to link the optional to the result object
568+
// of the call expression.
569+
auto &ResultLoc = State.Env.getResultObjectLocation(*CE);
570+
copyRecord(*cast<RecordStorageLocation>(Loc), ResultLoc, State.Env);
571+
}
572+
return;
573+
}
574+
575+
// Cache if the const method returns a boolean type.
576+
// We may decide to cache other return types in the future.
577+
if (RecordLoc != nullptr && CE->getType()->isBooleanType()) {
578+
Value *Val = State.Lattice.getOrCreateConstMethodReturnValue(*RecordLoc, CE,
579+
State.Env);
580+
if (Val == nullptr)
581+
return;
582+
State.Env.setValue(*CE, *Val);
583+
return;
584+
}
585+
586+
// Perform default handling if the call returns an optional
587+
// but wasn't handled above (if RecordLoc is nullptr).
588+
if (isSupportedOptionalType(CE->getType())) {
589+
transferCallReturningOptional(CE, Result, State);
590+
}
591+
}
592+
593+
void transferValue_ConstMemberCall(const CXXMemberCallExpr *MCE,
594+
const MatchFinder::MatchResult &Result,
595+
LatticeTransferState &State) {
596+
handleConstMemberCall(
597+
MCE, dataflow::getImplicitObjectLocation(*MCE, State.Env), Result, State);
598+
}
599+
600+
void handleNonConstMemberCall(const CallExpr *CE,
601+
dataflow::RecordStorageLocation *RecordLoc,
602+
const MatchFinder::MatchResult &Result,
603+
LatticeTransferState &State) {
604+
// When a non-const member function is called, reset some state.
605+
if (RecordLoc != nullptr) {
606+
for (const auto &[Field, FieldLoc] : RecordLoc->children()) {
607+
if (isSupportedOptionalType(Field->getType())) {
608+
auto *FieldRecordLoc = cast_or_null<RecordStorageLocation>(FieldLoc);
609+
if (FieldRecordLoc) {
610+
setHasValue(*FieldRecordLoc, State.Env.makeAtomicBoolValue(),
611+
State.Env);
612+
}
613+
}
614+
}
615+
State.Lattice.clearConstMethodReturnValues(*RecordLoc);
616+
State.Lattice.clearConstMethodReturnStorageLocations(*RecordLoc);
617+
}
618+
619+
// Perform default handling if the call returns an optional.
620+
if (isSupportedOptionalType(CE->getType())) {
621+
transferCallReturningOptional(CE, Result, State);
622+
}
623+
}
624+
625+
void transferValue_NonConstMemberCall(const CXXMemberCallExpr *MCE,
626+
const MatchFinder::MatchResult &Result,
627+
LatticeTransferState &State) {
628+
handleNonConstMemberCall(
629+
MCE, dataflow::getImplicitObjectLocation(*MCE, State.Env), Result, State);
630+
}
631+
632+
void transferValue_NonConstMemberOperatorCall(
633+
const CXXOperatorCallExpr *OCE, const MatchFinder::MatchResult &Result,
634+
LatticeTransferState &State) {
635+
auto *RecordLoc = cast_or_null<dataflow::RecordStorageLocation>(
636+
State.Env.getStorageLocation(*OCE->getArg(0)));
637+
handleNonConstMemberCall(OCE, RecordLoc, Result, State);
638+
}
639+
526640
void constructOptionalValue(const Expr &E, Environment &Env,
527641
BoolValue &HasValueVal) {
528642
RecordStorageLocation &Loc = Env.getResultObjectLocation(E);
@@ -899,7 +1013,17 @@ auto buildTransferMatchSwitch() {
8991013
transferOptionalAndValueCmp(Cmp, Cmp->getArg(1), State.Env);
9001014
})
9011015

902-
// returns optional
1016+
// const accessor calls
1017+
.CaseOfCFGStmt<CXXMemberCallExpr>(isZeroParamConstMemberCall(),
1018+
transferValue_ConstMemberCall)
1019+
// non-const member calls that may modify the state of an object.
1020+
.CaseOfCFGStmt<CXXMemberCallExpr>(isNonConstMemberCall(),
1021+
transferValue_NonConstMemberCall)
1022+
.CaseOfCFGStmt<CXXOperatorCallExpr>(
1023+
isNonConstMemberOperatorCall(),
1024+
transferValue_NonConstMemberOperatorCall)
1025+
1026+
// other cases of returning optional
9031027
.CaseOfCFGStmt<CallExpr>(isCallReturningOptional(),
9041028
transferCallReturningOptional)
9051029

@@ -958,7 +1082,8 @@ UncheckedOptionalAccessModel::optionalClassDecl() {
9581082

9591083
UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(ASTContext &Ctx,
9601084
Environment &Env)
961-
: DataflowAnalysis<UncheckedOptionalAccessModel, NoopLattice>(Ctx),
1085+
: DataflowAnalysis<UncheckedOptionalAccessModel,
1086+
UncheckedOptionalAccessLattice>(Ctx),
9621087
TransferMatchSwitch(buildTransferMatchSwitch()) {
9631088
Env.getDataflowAnalysisContext().setSyntheticFieldCallback(
9641089
[&Ctx](QualType Ty) -> llvm::StringMap<QualType> {
@@ -972,7 +1097,8 @@ UncheckedOptionalAccessModel::UncheckedOptionalAccessModel(ASTContext &Ctx,
9721097
}
9731098

9741099
void UncheckedOptionalAccessModel::transfer(const CFGElement &Elt,
975-
NoopLattice &L, Environment &Env) {
1100+
UncheckedOptionalAccessLattice &L,
1101+
Environment &Env) {
9761102
LatticeTransferState State(L, Env);
9771103
TransferMatchSwitch(Elt, getASTContext(), State);
9781104
}

clang/lib/Basic/Module.cpp

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@
3434

3535
using namespace clang;
3636

37-
Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
38-
bool IsFramework, bool IsExplicit, unsigned VisibilityID)
37+
Module::Module(ModuleConstructorTag, StringRef Name,
38+
SourceLocation DefinitionLoc, Module *Parent, bool IsFramework,
39+
bool IsExplicit, unsigned VisibilityID)
3940
: Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent),
4041
VisibilityID(VisibilityID), IsUnimportable(false),
4142
HasIncompatibleModuleFile(false), IsAvailable(true),
@@ -58,11 +59,7 @@ Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent,
5859
}
5960
}
6061

61-
Module::~Module() {
62-
for (auto *Submodule : SubModules) {
63-
delete Submodule;
64-
}
65-
}
62+
Module::~Module() = default;
6663

6764
static bool isPlatformEnvironment(const TargetInfo &Target, StringRef Feature) {
6865
StringRef Platform = Target.getPlatformName();
@@ -361,21 +358,6 @@ Module *Module::findSubmodule(StringRef Name) const {
361358
return SubModules[Pos->getValue()];
362359
}
363360

364-
Module *Module::findOrInferSubmodule(StringRef Name) {
365-
llvm::StringMap<unsigned>::const_iterator Pos = SubModuleIndex.find(Name);
366-
if (Pos != SubModuleIndex.end())
367-
return SubModules[Pos->getValue()];
368-
if (!InferSubmodules)
369-
return nullptr;
370-
Module *Result = new Module(Name, SourceLocation(), this, false, InferExplicitSubmodules, 0);
371-
Result->InferExplicitSubmodules = InferExplicitSubmodules;
372-
Result->InferSubmodules = InferSubmodules;
373-
Result->InferExportWildcard = InferExportWildcard;
374-
if (Result->InferExportWildcard)
375-
Result->Exports.push_back(Module::ExportDecl(nullptr, true));
376-
return Result;
377-
}
378-
379361
Module *Module::getGlobalModuleFragment() const {
380362
assert(isNamedModuleUnit() && "We should only query the global module "
381363
"fragment from the C++20 Named modules");

clang/lib/Basic/Targets/AMDGPU.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,9 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple,
260260
void AMDGPUTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
261261
TargetInfo::adjust(Diags, Opts);
262262
// ToDo: There are still a few places using default address space as private
263-
// address space in OpenCL, which needs to be cleaned up, then Opts.OpenCL
264-
// can be removed from the following line.
265-
setAddressSpaceMap(/*DefaultIsPrivate=*/Opts.OpenCL ||
263+
// address space in OpenCL, which needs to be cleaned up, then the references
264+
// to OpenCL can be removed from the following line.
265+
setAddressSpaceMap((Opts.OpenCL && !Opts.OpenCLGenericAddressSpace) ||
266266
!isAMDGCN(getTriple()));
267267
}
268268

0 commit comments

Comments
 (0)