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:
Richard Smith 2016-03-25 21:49:43 +00:00
parent 020e890a19
commit d6a04d79c7
8 changed files with 36 additions and 35 deletions

View File

@ -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>> &);

View File

@ -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>> &

View File

@ -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(

View File

@ -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>> &

View File

@ -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);
}

View File

@ -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>> &) {}

View File

@ -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 =

View File

@ -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