#include "clang/AST/Decl.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/PointerIntPair.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
/// popped, these declarations are removed from the IdentifierTable's notion
/// of current declaration. It is up to the current Action implementation to
/// implement these semantics.
- using DeclSetTy = llvm::SmallSetVector<Decl *, 32>;
+ using DeclSetTy = llvm::SmallPtrSet<Decl *, 32>;
DeclSetTy DeclsInScope;
/// The DeclContext with which this scope is associated. For
DeclsInScope.insert(D);
}
- void RemoveDecl(Decl *D) { DeclsInScope.remove(D); }
+ void RemoveDecl(Decl *D) { DeclsInScope.erase(D); }
void incrementMSManglingNumber() {
if (Scope *MSLMP = getMSLastManglingParent()) {
/// isDeclScope - Return true if this is the scope that the specified decl is
/// declared in.
- bool isDeclScope(const Decl *D) const {
- return DeclsInScope.contains(const_cast<Decl *>(D));
- }
+ bool isDeclScope(const Decl *D) const { return DeclsInScope.contains(D); }
/// Get the entity corresponding to this scope.
DeclContext *getEntity() const {
}
void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) {
+ DiagnoseUnusedNestedTypedefs(
+ D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
+}
+
+void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D,
+ DiagReceiverTy DiagReceiver) {
if (D->getTypeForDecl()->isDependentType())
return;
for (auto *TmpD : D->decls()) {
if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD))
- DiagnoseUnusedDecl(T);
+ DiagnoseUnusedDecl(T, DiagReceiver);
else if(const auto *R = dyn_cast<RecordDecl>(TmpD))
- DiagnoseUnusedNestedTypedefs(R);
+ DiagnoseUnusedNestedTypedefs(R, DiagReceiver);
}
}
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+ DiagnoseUnusedDecl(
+ D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); });
+}
+
/// DiagnoseUnusedDecl - Emit warnings about declarations that are not used
/// unless they are marked attr(unused).
-void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
+void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver) {
if (!ShouldDiagnoseUnusedDecl(D))
return;
else
DiagID = diag::warn_unused_variable;
- Diag(D->getLocation(), DiagID) << D << Hint;
+ DiagReceiver(D->getLocation(), PDiag(DiagID) << D << Hint);
}
-void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) {
+void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD,
+ DiagReceiverTy DiagReceiver) {
// If it's not referenced, it can't be set. If it has the Cleanup attribute,
// it's not really unused.
if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr<UnusedAttr>() ||
return;
unsigned DiagID = isa<ParmVarDecl>(VD) ? diag::warn_unused_but_set_parameter
: diag::warn_unused_but_set_variable;
- Diag(VD->getLocation(), DiagID) << VD;
+ DiagReceiver(VD->getLocation(), PDiag(DiagID) << VD);
}
-static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
+static void CheckPoppedLabel(LabelDecl *L, Sema &S,
+ Sema::DiagReceiverTy DiagReceiver) {
// Verify that we have no forward references left. If so, there was a goto
// or address of a label taken, but no definition of it. Label fwd
// definitions are indicated with a null substmt which is also not a resolved
else
Diagnose = L->getStmt() == nullptr;
if (Diagnose)
- S.Diag(L->getLocation(), diag::err_undeclared_label_use) << L;
+ DiagReceiver(L->getLocation(), S.PDiag(diag::err_undeclared_label_use)
+ << L);
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
"Scope shouldn't contain decls!");
+ /// We visit the decls in non-deterministic order, but we want diagnostics
+ /// emitted in deterministic order. Collect any diagnostic that may be emitted
+ /// and sort the diagnostics before emitting them, after we visited all decls.
+ struct LocAndDiag {
+ SourceLocation Loc;
+ Optional<SourceLocation> PreviousDeclLoc;
+ PartialDiagnostic PD;
+ };
+ SmallVector<LocAndDiag, 16> DeclDiags;
+ auto addDiag = [&DeclDiags](SourceLocation Loc, PartialDiagnostic PD) {
+ DeclDiags.push_back(LocAndDiag{Loc, None, std::move(PD)});
+ };
+ auto addDiagWithPrev = [&DeclDiags](SourceLocation Loc,
+ SourceLocation PreviousDeclLoc,
+ PartialDiagnostic PD) {
+ DeclDiags.push_back(LocAndDiag{Loc, PreviousDeclLoc, std::move(PD)});
+ };
+
for (auto *TmpD : S->decls()) {
assert(TmpD && "This decl didn't get pushed??");
// Diagnose unused variables in this scope.
if (!S->hasUnrecoverableErrorOccurred()) {
- DiagnoseUnusedDecl(D);
+ DiagnoseUnusedDecl(D, addDiag);
if (const auto *RD = dyn_cast<RecordDecl>(D))
- DiagnoseUnusedNestedTypedefs(RD);
+ DiagnoseUnusedNestedTypedefs(RD, addDiag);
if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
- DiagnoseUnusedButSetDecl(VD);
+ DiagnoseUnusedButSetDecl(VD, addDiag);
RefsMinusAssignments.erase(VD);
}
}
// If this was a forward reference to a label, verify it was defined.
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
- CheckPoppedLabel(LD, *this);
+ CheckPoppedLabel(LD, *this, addDiag);
// Remove this name from our lexical scope, and warn on it if we haven't
// already.
auto ShadowI = ShadowingDecls.find(D);
if (ShadowI != ShadowingDecls.end()) {
if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) {
- Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field)
- << D << FD << FD->getParent();
- Diag(FD->getLocation(), diag::note_previous_declaration);
+ addDiagWithPrev(D->getLocation(), FD->getLocation(),
+ PDiag(diag::warn_ctor_parm_shadows_field)
+ << D << FD << FD->getParent());
}
ShadowingDecls.erase(ShadowI);
}
}
+
+ llvm::sort(DeclDiags,
+ [](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool {
+ // The particular order for diagnostics is not important, as long
+ // as the order is deterministic. Using the raw location is going
+ // to generally be in source order unless there are macro
+ // expansions involved.
+ return LHS.Loc.getRawEncoding() < RHS.Loc.getRawEncoding();
+ });
+ for (const LocAndDiag &D : DeclDiags) {
+ Diag(D.Loc, D.PD);
+ if (D.PreviousDeclLoc)
+ Diag(*D.PreviousDeclLoc, diag::note_previous_declaration);
+ }
}
/// Look for an Objective-C class in the translation unit.