From fff3553f38ef98f6fb6bad4adbbb78d526bfcc0b Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 25 Mar 2016 21:49:43 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@264466 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/ExternalSemaSource.h | 4 +- .../clang/Sema/MultiplexExternalSemaSource.h | 2 +- include/clang/Sema/Sema.h | 2 +- include/clang/Serialization/ASTReader.h | 2 +- lib/Sema/MultiplexExternalSemaSource.cpp | 2 +- lib/Sema/Sema.cpp | 39 ++++++------------- lib/Serialization/ASTReader.cpp | 2 +- test/SemaCXX/diagnostic-order.cpp | 18 ++++++++- 8 files changed, 36 insertions(+), 35 deletions(-) diff --git a/include/clang/Sema/ExternalSemaSource.h b/include/clang/Sema/ExternalSemaSource.h index 97f78f46a6..2fdc42b1ac 100644 --- a/include/clang/Sema/ExternalSemaSource.h +++ b/include/clang/Sema/ExternalSemaSource.h @@ -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 &Undefined); + virtual void + ReadUndefinedButUsed(llvm::MapVector &Undefined); virtual void ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> &); diff --git a/include/clang/Sema/MultiplexExternalSemaSource.h b/include/clang/Sema/MultiplexExternalSemaSource.h index d6daadc89d..5f43f4051a 100644 --- a/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/include/clang/Sema/MultiplexExternalSemaSource.h @@ -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 &Undefined) override; + llvm::MapVector &Undefined) override; void ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> & diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 377fb182a4..cd7fe6c8a2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -941,7 +941,7 @@ public: /// UndefinedInternals - all the used, undefined objects which require a /// definition in this translation unit. - llvm::DenseMap UndefinedButUsed; + llvm::MapVector UndefinedButUsed; /// Obtain a sorted list of functions that are undefined but ODR-used. void getUndefinedButUsed( diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index e789c1e9d1..74424fb44b 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -1807,7 +1807,7 @@ public: SmallVectorImpl &Namespaces) override; void ReadUndefinedButUsed( - llvm::DenseMap &Undefined) override; + llvm::MapVector &Undefined) override; void ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> & diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp index 0f93421ac2..89eec242eb 100644 --- a/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/lib/Sema/MultiplexExternalSemaSource.cpp @@ -204,7 +204,7 @@ void MultiplexExternalSemaSource::ReadKnownNamespaces( } void MultiplexExternalSemaSource::ReadUndefinedButUsed( - llvm::DenseMap &Undefined){ + llvm::MapVector &Undefined) { for(size_t i = 0; i < Sources.size(); ++i) Sources[i]->ReadUndefinedButUsed(Undefined); } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 584dca1e38..997d967aa1 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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 > &Undefined) { - for (llvm::DenseMap::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 &l, - const std::pair &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 &Undefined) { -} + llvm::MapVector &Undefined) {} void ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector, 4>> &) {} diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index f730d6f4f2..d05cbeb2a1 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -7254,7 +7254,7 @@ void ASTReader::ReadKnownNamespaces( } void ASTReader::ReadUndefinedButUsed( - llvm::DenseMap &Undefined) { + llvm::MapVector &Undefined) { for (unsigned Idx = 0, N = UndefinedButUsed.size(); Idx != N;) { NamedDecl *D = cast(GetDecl(UndefinedButUsed[Idx++])); SourceLocation Loc = diff --git a/test/SemaCXX/diagnostic-order.cpp b/test/SemaCXX/diagnostic-order.cpp index b3b270bfc9..4ced22c92a 100644 --- a/test/SemaCXX/diagnostic-order.cpp +++ b/test/SemaCXX/diagnostic-order.cpp @@ -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' // CHECK: no type named 'error' in 'Oper' // CHECK: in instantiation of template class 'Error' + +#endif + +template struct UndefButUsed { + static inline int f(); + static int g() { return f(); } +}; +int undef_but_used = UndefButUsed::g() + UndefButUsed::g() + UndefButUsed::g() + UndefButUsed::g(); + +// CHECK-WARN: inline function 'UndefButUsed::f' is not defined +// CHECK-WARN: inline function 'UndefButUsed::f' is not defined +// CHECK-WARN: inline function 'UndefButUsed::f' is not defined +// CHECK-WARN: inline function 'UndefButUsed::f' is not defined -- 2.40.0