mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-15 12:39:19 +00:00
Store list of undefined-but-used objects in a deterministic order to fix
non-deterministic diagnostics (and non-deterministic PCH files). Check these when building a module rather than serializing it; it's not reasonable for a module's use to be satisfied by a definition in the user of the module. llvm-svn: 264466
This commit is contained in:
parent
020e890a19
commit
d6a04d79c7
@ -77,8 +77,8 @@ public:
|
||||
|
||||
/// \brief Load the set of used but not defined functions or variables with
|
||||
/// internal linkage, or used but not defined internal functions.
|
||||
virtual void ReadUndefinedButUsed(
|
||||
llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined);
|
||||
virtual void
|
||||
ReadUndefinedButUsed(llvm::MapVector<NamedDecl *, SourceLocation> &Undefined);
|
||||
|
||||
virtual void ReadMismatchingDeleteExpressions(llvm::MapVector<
|
||||
FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &);
|
||||
|
@ -211,7 +211,7 @@ public:
|
||||
/// \brief Load the set of used but not defined functions or variables with
|
||||
/// internal linkage, or used but not defined inline functions.
|
||||
void ReadUndefinedButUsed(
|
||||
llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) override;
|
||||
llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) override;
|
||||
|
||||
void ReadMismatchingDeleteExpressions(llvm::MapVector<
|
||||
FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &
|
||||
|
@ -941,7 +941,7 @@ public:
|
||||
|
||||
/// UndefinedInternals - all the used, undefined objects which require a
|
||||
/// definition in this translation unit.
|
||||
llvm::DenseMap<NamedDecl *, SourceLocation> UndefinedButUsed;
|
||||
llvm::MapVector<NamedDecl *, SourceLocation> UndefinedButUsed;
|
||||
|
||||
/// Obtain a sorted list of functions that are undefined but ODR-used.
|
||||
void getUndefinedButUsed(
|
||||
|
@ -1807,7 +1807,7 @@ public:
|
||||
SmallVectorImpl<NamespaceDecl *> &Namespaces) override;
|
||||
|
||||
void ReadUndefinedButUsed(
|
||||
llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) override;
|
||||
llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) override;
|
||||
|
||||
void ReadMismatchingDeleteExpressions(llvm::MapVector<
|
||||
FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &
|
||||
|
@ -204,7 +204,7 @@ void MultiplexExternalSemaSource::ReadKnownNamespaces(
|
||||
}
|
||||
|
||||
void MultiplexExternalSemaSource::ReadUndefinedButUsed(
|
||||
llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined){
|
||||
llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) {
|
||||
for(size_t i = 0; i < Sources.size(); ++i)
|
||||
Sources[i]->ReadUndefinedButUsed(Undefined);
|
||||
}
|
||||
|
@ -478,10 +478,8 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
|
||||
/// Obtains a sorted list of functions that are undefined but ODR-used.
|
||||
void Sema::getUndefinedButUsed(
|
||||
SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined) {
|
||||
for (llvm::DenseMap<NamedDecl *, SourceLocation>::iterator
|
||||
I = UndefinedButUsed.begin(), E = UndefinedButUsed.end();
|
||||
I != E; ++I) {
|
||||
NamedDecl *ND = I->first;
|
||||
for (const auto &UndefinedUse : UndefinedButUsed) {
|
||||
NamedDecl *ND = UndefinedUse.first;
|
||||
|
||||
// Ignore attributes that have become invalid.
|
||||
if (ND->isInvalidDecl()) continue;
|
||||
@ -502,24 +500,8 @@ void Sema::getUndefinedButUsed(
|
||||
continue;
|
||||
}
|
||||
|
||||
Undefined.push_back(std::make_pair(ND, I->second));
|
||||
Undefined.push_back(std::make_pair(ND, UndefinedUse.second));
|
||||
}
|
||||
|
||||
// Sort (in order of use site) so that we're not dependent on the iteration
|
||||
// order through an llvm::DenseMap.
|
||||
SourceManager &SM = Context.getSourceManager();
|
||||
std::sort(Undefined.begin(), Undefined.end(),
|
||||
[&SM](const std::pair<NamedDecl *, SourceLocation> &l,
|
||||
const std::pair<NamedDecl *, SourceLocation> &r) {
|
||||
if (l.second.isValid() && !r.second.isValid())
|
||||
return true;
|
||||
if (!l.second.isValid() && r.second.isValid())
|
||||
return false;
|
||||
if (l.second != r.second)
|
||||
return SM.isBeforeInTranslationUnit(l.second, r.second);
|
||||
return SM.isBeforeInTranslationUnit(l.first->getLocation(),
|
||||
r.first->getLocation());
|
||||
});
|
||||
}
|
||||
|
||||
/// checkUndefinedButUsed - Check for undefined objects with internal linkage
|
||||
@ -554,6 +536,8 @@ static void checkUndefinedButUsed(Sema &S) {
|
||||
if (I->second.isValid())
|
||||
S.Diag(I->second, diag::note_used_here);
|
||||
}
|
||||
|
||||
S.UndefinedButUsed.clear();
|
||||
}
|
||||
|
||||
void Sema::LoadExternalWeakUndeclaredIdentifiers() {
|
||||
@ -749,6 +733,12 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||
!Diags.isIgnored(diag::warn_delegating_ctor_cycle, SourceLocation()))
|
||||
CheckDelegatingCtorCycles();
|
||||
|
||||
if (!Diags.hasErrorOccurred()) {
|
||||
if (ExternalSource)
|
||||
ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
|
||||
checkUndefinedButUsed(*this);
|
||||
}
|
||||
|
||||
if (TUKind == TU_Module) {
|
||||
// If we are building a module, resolve all of the exported declarations
|
||||
// now.
|
||||
@ -882,10 +872,6 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||
}
|
||||
}
|
||||
|
||||
if (ExternalSource)
|
||||
ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
|
||||
checkUndefinedButUsed(*this);
|
||||
|
||||
emitAndClearUnusedLocalTypedefWarnings();
|
||||
}
|
||||
|
||||
@ -1271,8 +1257,7 @@ void ExternalSemaSource::ReadKnownNamespaces(
|
||||
}
|
||||
|
||||
void ExternalSemaSource::ReadUndefinedButUsed(
|
||||
llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) {
|
||||
}
|
||||
llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) {}
|
||||
|
||||
void ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector<
|
||||
FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &) {}
|
||||
|
@ -7254,7 +7254,7 @@ void ASTReader::ReadKnownNamespaces(
|
||||
}
|
||||
|
||||
void ASTReader::ReadUndefinedButUsed(
|
||||
llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined) {
|
||||
llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) {
|
||||
for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) {
|
||||
NamedDecl *D = cast<NamedDecl>(GetDecl(UndefinedButUsed[Idx++]));
|
||||
SourceLocation Loc =
|
||||
|
@ -1,4 +1,7 @@
|
||||
// RUN: not %clang_cc1 %s -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: not %clang_cc1 -std=c++11 %s -fsyntax-only 2>&1 | FileCheck %s
|
||||
// RUN: %clang_cc1 -std=c++11 %s -fsyntax-only -DWARN 2>&1 | FileCheck %s --check-prefix=CHECK-WARN
|
||||
|
||||
#ifndef WARN
|
||||
|
||||
// Ensure that the diagnostics we produce for this situation appear in a
|
||||
// deterministic order. This requires ADL to provide lookup results in a
|
||||
@ -55,3 +58,16 @@ int *p = Oper() + 0;
|
||||
// CHECK: in instantiation of template class 'Error<Oper, X *>'
|
||||
// CHECK: no type named 'error' in 'Oper'
|
||||
// CHECK: in instantiation of template class 'Error<Oper, Y *>'
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T> struct UndefButUsed {
|
||||
static inline int f();
|
||||
static int g() { return f(); }
|
||||
};
|
||||
int undef_but_used = UndefButUsed<int>::g() + UndefButUsed<float>::g() + UndefButUsed<char>::g() + UndefButUsed<void>::g();
|
||||
|
||||
// CHECK-WARN: inline function 'UndefButUsed<int>::f' is not defined
|
||||
// CHECK-WARN: inline function 'UndefButUsed<float>::f' is not defined
|
||||
// CHECK-WARN: inline function 'UndefButUsed<char>::f' is not defined
|
||||
// CHECK-WARN: inline function 'UndefButUsed<void>::f' is not defined
|
||||
|
Loading…
x
Reference in New Issue
Block a user