On Apr 28, 2014, at 4:33 PM, Richard Smith <rich...@metafoo.co.uk> wrote:
> I would marginally prefer using < DiagnosticsEngine::Error rather than <= > DiagnosticsEngine::Warning, since I think it's clearer about what we're > testing for. Sure. > > + ModuleFile *TopImport = *ModuleMgr.rbegin(); > > Are we guaranteed that the last-imported ModuleFile is the one we're > validating at this point? (What happens if we read the diagnostic options > block after we read the imported modules block?) It actually isn’t the currently validating module (unless it is a leaf). But it must be in the transitive closure of its imports, so it ends up finding the same top-level import. Ben > > Other than that, LGTM, thanks! > > > On Mon, Apr 28, 2014 at 4:22 PM, Ben Langmuir <blangm...@apple.com> wrote: > Updated patch attached. > > Ben > > > > On Apr 28, 2014, at 3:02 PM, Ben Langmuir <blangm...@apple.com> wrote: > >> >> On Apr 28, 2014, at 2:13 PM, Richard Smith <rich...@metafoo.co.uk> wrote: >> >>> On Sat, Apr 26, 2014 at 8:35 PM, Ben Langmuir <blangm...@apple.com> wrote: >>> As discussed here >>> http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20140414/103530.html >>> >>> This patch checks whether the diagnostic options that could lead to errors >>> (principally -Werror) are consistent between when a module was built and >>> when it is loaded. If there are new -Werror flags, then the module is >>> rebuilt. In order to canonicalize the options we do this check at the >>> level of the constructed DiagnosticsEngine, which contains the final set of >>> diag to diagnostic level mappings. Currently we only rebuild with the new >>> diagnostic options, but we intend to refine this in the future to include >>> the union of the new and old flags, since we know the old ones did not >>> cause errors. System modules are only rebuilt when -Wsystem-headers is >>> enabled. >>> >>> One oddity is that unlike checking language options, we don’t perform this >>> diagnostic option checking when loading from a precompiled header. The >>> reason for this is that the compiler cannot rebuild the PCH, so anything >>> that requires it to be rebuilt effectively leaks into the build system. >>> And in this case, that would mean the build system understanding the >>> complex relationship between diagnostic options and the underlying >>> diagnostic mappings, which is unreasonable. >>> >>> More than that, if the AST file was explicitly built by the user, they may >>> *intend* to apply different warning flags to the two cases, and we >>> shouldn't stop them from doing that. (Likewise, we will eventually want a >>> properly-productized way to explicitly build modules, and this constraint >>> shouldn't apply to such explicitly-built modules either.) >> >> Makes sense to me. >> >>> >>> Skipping the check is safe, because these options do not affect the >>> generated AST. You simply won’t get new build errors due to changed >>> -Werror options automatically, which is also true for non-module cases. >>> >>> @@ -4481,18 +4579,18 @@ bool ASTReader::ParseTargetOptions(const RecordData >>> &Record, >>> >>> bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool >>> Complain, >>> ASTReaderListener &Listener) { >>> - DiagnosticOptions DiagOpts; >>> + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions); >>> unsigned Idx = 0; >>> -#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++]; >>> +#define DIAGOPT(Name, Bits, Default) DiagOpts->Name = Record[Idx++]; >>> #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ >>> - DiagOpts.set##Name(static_cast<Type>(Record[Idx++])); >>> + DiagOpts->set##Name(static_cast<Type>(Record[Idx++])); >>> #include "clang/Basic/DiagnosticOptions.def" >>> >>> for (unsigned N = Record[Idx++]; N; --N) { >>> - DiagOpts.Warnings.push_back(ReadString(Record, Idx)); >>> + DiagOpts->Warnings.push_back(ReadString(Record, Idx)); >>> } >>> >>> - return Listener.ReadDiagnosticOptions(DiagOpts, Complain); >>> + return Listener.ReadDiagnosticOptions(*DiagOpts, Complain); >>> } >>> >>> bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool >>> Complain, >>> >>> >>> This change suggests that the interface to ReadDiagnosticOptions has become >>> error-prone: if we now need the DiagnosticOptions object to outlive the >>> call to ReadDiagnosticOptions, it should not be passed by const reference. >>> If we need it to be allocated inside an IntrusiveRefCntPtr, we should >>> require that in the interface. What's going on here? >> >> The latter. DiagnosticsEngine expects DiagOpts to be an IntrusiveRefCntPtr. >> I will change the interfaces to use the correct types. >> >>> >>> >>> + if ((*ModuleMgr.begin())->Kind != serialization::MK_Module) >>> + return false; >>> >>> This doesn't look quite right. We could be loading a new module file that's >>> unrelated to the PCH or preamble, and in that case we should apply these >>> checks. >> >> True. I suppose iterating ImportedBy[0] is good enough to tell us whether >> this came from an MK_Module or not. >> >>> >>> >>> + // Check current mappings for new -Werror mappings >>> + for (auto DiagIDMappingPair : Diags.getDiagnosticMappings()) { >>> + diag::kind DiagID = DiagIDMappingPair.first; >>> + Level CurLevel = Diags.getDiagnosticLevel(DiagID, SourceLocation()); >>> + if (CurLevel <= DiagnosticsEngine::Warning) >>> + continue; // not significant >>> + Level StoredLevel = StoredDiags.getDiagnosticLevel(DiagID, >>> SourceLocation()); >>> + if (StoredLevel <= DiagnosticsEngine::Warning) { >>> + if (Complain) >>> + Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror=" + >>> + >>> Diags.getDiagnosticIDs()->getWarningOptionForDiag(DiagID).str(); >>> + return true; >>> + } >>> + } >>> + >>> + // Check the stored mappings for cases that were explicitly mapped to >>> *not* be >>> + // errors that are now errors because of options like -Werror. >>> + for (auto DiagIDMappingPair : StoredDiags.getDiagnosticMappings()) { >>> + diag::kind DiagID = DiagIDMappingPair.first; >>> + Level StoredLevel = StoredDiags.getDiagnosticLevel(DiagID, >>> SourceLocation()); >>> + if (StoredLevel >= DiagnosticsEngine::Error) >>> + continue; // already an error >>> + Level CurLevel = Diags.getDiagnosticLevel(DiagID, SourceLocation()); >>> + if (CurLevel >= DiagnosticsEngine::Error) { >>> + if (Complain) >>> + Diags.Report(diag::err_pch_diagopt_mismatch) << "-Werror=" + >>> + >>> Diags.getDiagnosticIDs()->getWarningOptionForDiag(DiagID).str(); >>> + return true; >>> + } >>> + } >>> >>> Your two loop bodies are semantically identical; can you factor out the >>> redundancy here? (I guess you're duplicating this to try to avoid adding >>> extra diagnostic mapping entries?) >>> >> Sure, I can simplify this. >> >>> >>> +static bool checkDiagnosticMappings(DiagnosticsEngine &StoredDiags, >>> + DiagnosticsEngine &Diags, >>> + bool IsSystem, bool Complain) { >>> >>> We should also check for differences in ExtBehavior here (in case the user >>> has enabled -fpedantic-errors). >> >> Yes we should! > > >
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits