diff options
Diffstat (limited to 'lib/Serialization')
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 244 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 3 |
3 files changed, 215 insertions, 35 deletions
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 111ac4fcdaa4..4ed822e04f6c 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -9235,8 +9235,16 @@ void ASTReader::finishPendingActions() { const FunctionDecl *Defn = nullptr; if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn)) { FD->setLazyBody(PB->second); - } else - mergeDefinitionVisibility(const_cast<FunctionDecl*>(Defn), FD); + } else { + auto *NonConstDefn = const_cast<FunctionDecl*>(Defn); + mergeDefinitionVisibility(NonConstDefn, FD); + + if (!FD->isLateTemplateParsed() && + !NonConstDefn->isLateTemplateParsed() && + FD->getODRHash() != NonConstDefn->getODRHash()) { + PendingFunctionOdrMergeFailures[FD].push_back(NonConstDefn); + } + } continue; } @@ -9253,7 +9261,8 @@ void ASTReader::finishPendingActions() { } void ASTReader::diagnoseOdrViolations() { - if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty()) + if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() && + PendingFunctionOdrMergeFailures.empty()) return; // Trigger the import of the full definition of each class that had any @@ -9275,6 +9284,20 @@ void ASTReader::diagnoseOdrViolations() { } } + // Trigger the import of functions. + auto FunctionOdrMergeFailures = std::move(PendingFunctionOdrMergeFailures); + PendingFunctionOdrMergeFailures.clear(); + for (auto &Merge : FunctionOdrMergeFailures) { + Merge.first->buildLookup(); + Merge.first->decls_begin(); + Merge.first->getBody(); + for (auto &FD : Merge.second) { + FD->buildLookup(); + FD->decls_begin(); + FD->getBody(); + } + } + // For each declaration from a merged context, check that the canonical // definition of that context also contains a declaration of the same // entity. @@ -9357,13 +9380,35 @@ void ASTReader::diagnoseOdrViolations() { } } - if (OdrMergeFailures.empty()) + if (OdrMergeFailures.empty() && FunctionOdrMergeFailures.empty()) return; // Ensure we don't accidentally recursively enter deserialization while // we're producing our diagnostics. Deserializing RecursionGuard(this); + // Common code for hashing helpers. + ODRHash Hash; + auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { + Hash.clear(); + Hash.AddQualType(Ty); + return Hash.CalculateHash(); + }; + + auto ComputeODRHash = [&Hash](const Stmt *S) { + assert(S); + Hash.clear(); + Hash.AddStmt(S); + return Hash.CalculateHash(); + }; + + auto ComputeSubDeclODRHash = [&Hash](const Decl *D) { + assert(D); + Hash.clear(); + Hash.AddSubDecl(D); + return Hash.CalculateHash(); + }; + // Issue any pending ODR-failure diagnostics. for (auto &Merge : OdrMergeFailures) { // If we've already pointed out a specific problem with this class, don't @@ -9411,13 +9456,6 @@ void ASTReader::diagnoseOdrViolations() { << SecondModule << Range << DiffType; }; - ODRHash Hash; - auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { - Hash.clear(); - Hash.AddQualType(Ty); - return Hash.CalculateHash(); - }; - unsigned FirstNumBases = FirstDD->NumBases; unsigned FirstNumVBases = FirstDD->NumVBases; unsigned SecondNumBases = SecondDD->NumBases; @@ -9520,14 +9558,12 @@ void ASTReader::diagnoseOdrViolations() { if (FirstTemplate && SecondTemplate) { DeclHashes FirstTemplateHashes; DeclHashes SecondTemplateHashes; - ODRHash Hash; auto PopulateTemplateParameterHashs = - [&Hash](DeclHashes &Hashes, const ClassTemplateDecl *TD) { + [&ComputeSubDeclODRHash](DeclHashes &Hashes, + const ClassTemplateDecl *TD) { for (auto *D : TD->getTemplateParameters()->asArray()) { - Hash.clear(); - Hash.AddSubDecl(D); - Hashes.emplace_back(D, Hash.CalculateHash()); + Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); } }; @@ -9696,18 +9732,15 @@ void ASTReader::diagnoseOdrViolations() { DeclHashes FirstHashes; DeclHashes SecondHashes; - ODRHash Hash; - auto PopulateHashes = [&Hash, FirstRecord](DeclHashes &Hashes, - CXXRecordDecl *Record) { + auto PopulateHashes = [&ComputeSubDeclODRHash, FirstRecord]( + DeclHashes &Hashes, CXXRecordDecl *Record) { for (auto *D : Record->decls()) { // Due to decl merging, the first CXXRecordDecl is the parent of // Decls in both records. if (!ODRHash::isWhitelistedDecl(D, FirstRecord)) continue; - Hash.clear(); - Hash.AddSubDecl(D); - Hashes.emplace_back(D, Hash.CalculateHash()); + Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); } }; PopulateHashes(FirstHashes, FirstRecord); @@ -9901,19 +9934,6 @@ void ASTReader::diagnoseOdrViolations() { << SecondModule << Range << DiffType; }; - auto ComputeODRHash = [&Hash](const Stmt* S) { - assert(S); - Hash.clear(); - Hash.AddStmt(S); - return Hash.CalculateHash(); - }; - - auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { - Hash.clear(); - Hash.AddQualType(Ty); - return Hash.CalculateHash(); - }; - switch (FirstDiffType) { case Other: case EndOfClass: @@ -10488,6 +10508,160 @@ void ASTReader::diagnoseOdrViolations() { << Merge.first; } } + + // Issue ODR failures diagnostics for functions. + for (auto &Merge : FunctionOdrMergeFailures) { + enum ODRFunctionDifference { + ReturnType, + ParameterName, + ParameterType, + ParameterSingleDefaultArgument, + ParameterDifferentDefaultArgument, + FunctionBody, + }; + + FunctionDecl *FirstFunction = Merge.first; + std::string FirstModule = getOwningModuleNameForDiagnostic(FirstFunction); + + bool Diagnosed = false; + for (auto &SecondFunction : Merge.second) { + + if (FirstFunction == SecondFunction) + continue; + + std::string SecondModule = + getOwningModuleNameForDiagnostic(SecondFunction); + + auto ODRDiagError = [FirstFunction, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODRFunctionDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_function) + << FirstFunction << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagNote = [&SecondModule, this](SourceLocation Loc, + SourceRange Range, + ODRFunctionDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_function) + << SecondModule << Range << DiffType; + }; + + if (ComputeQualTypeODRHash(FirstFunction->getReturnType()) != + ComputeQualTypeODRHash(SecondFunction->getReturnType())) { + ODRDiagError(FirstFunction->getReturnTypeSourceRange().getBegin(), + FirstFunction->getReturnTypeSourceRange(), ReturnType) + << FirstFunction->getReturnType(); + ODRDiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(), + SecondFunction->getReturnTypeSourceRange(), ReturnType) + << SecondFunction->getReturnType(); + Diagnosed = true; + break; + } + + assert(FirstFunction->param_size() == SecondFunction->param_size() && + "Merged functions with different number of parameters"); + + auto ParamSize = FirstFunction->param_size(); + bool ParameterMismatch = false; + for (unsigned I = 0; I < ParamSize; ++I) { + auto *FirstParam = FirstFunction->getParamDecl(I); + auto *SecondParam = SecondFunction->getParamDecl(I); + + assert(getContext().hasSameType(FirstParam->getType(), + SecondParam->getType()) && + "Merged function has different parameter types."); + + if (FirstParam->getDeclName() != SecondParam->getDeclName()) { + ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), + ParameterName) + << I + 1 << FirstParam->getDeclName(); + ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), + ParameterName) + << I + 1 << SecondParam->getDeclName(); + ParameterMismatch = true; + break; + }; + + QualType FirstParamType = FirstParam->getType(); + QualType SecondParamType = SecondParam->getType(); + if (FirstParamType != SecondParamType && + ComputeQualTypeODRHash(FirstParamType) != + ComputeQualTypeODRHash(SecondParamType)) { + if (const DecayedType *ParamDecayedType = + FirstParamType->getAs<DecayedType>()) { + ODRDiagError(FirstParam->getLocation(), + FirstParam->getSourceRange(), ParameterType) + << (I + 1) << FirstParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagError(FirstParam->getLocation(), + FirstParam->getSourceRange(), ParameterType) + << (I + 1) << FirstParamType << false; + } + + if (const DecayedType *ParamDecayedType = + SecondParamType->getAs<DecayedType>()) { + ODRDiagNote(SecondParam->getLocation(), + SecondParam->getSourceRange(), ParameterType) + << (I + 1) << SecondParamType << true + << ParamDecayedType->getOriginalType(); + } else { + ODRDiagNote(SecondParam->getLocation(), + SecondParam->getSourceRange(), ParameterType) + << (I + 1) << SecondParamType << false; + } + ParameterMismatch = true; + break; + } + + const Expr *FirstInit = FirstParam->getInit(); + const Expr *SecondInit = SecondParam->getInit(); + if ((FirstInit == nullptr) != (SecondInit == nullptr)) { + ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), + ParameterSingleDefaultArgument) + << (I + 1) << (FirstInit == nullptr) + << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); + ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), + ParameterSingleDefaultArgument) + << (I + 1) << (SecondInit == nullptr) + << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); + ParameterMismatch = true; + break; + } + + if (FirstInit && SecondInit && + ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), + ParameterDifferentDefaultArgument) + << (I + 1) << FirstInit->getSourceRange(); + ODRDiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), + ParameterDifferentDefaultArgument) + << (I + 1) << SecondInit->getSourceRange(); + ParameterMismatch = true; + break; + } + + assert(ComputeSubDeclODRHash(FirstParam) == + ComputeSubDeclODRHash(SecondParam) && + "Undiagnosed parameter difference."); + } + + if (ParameterMismatch) { + Diagnosed = true; + break; + } + + // If no error has been generated before now, assume the problem is in + // the body and generate a message. + ODRDiagError(FirstFunction->getLocation(), + FirstFunction->getSourceRange(), FunctionBody); + ODRDiagNote(SecondFunction->getLocation(), + SecondFunction->getSourceRange(), FunctionBody); + Diagnosed = true; + break; + } + assert(Diagnosed && "Unable to emit ODR diagnostic."); + } } void ASTReader::StartedDeserializing() { diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index a3bf0d971267..efbaf92a849a 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -796,6 +796,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setCachedLinkage(Linkage(Record.readInt())); FD->EndRangeLoc = ReadSourceLocation(); + FD->ODRHash = Record.readInt(); + FD->HasODRHash = true; + switch ((FunctionDecl::TemplatedKind)Record.readInt()) { case FunctionDecl::TK_NonTemplate: mergeRedeclarable(FD, Redecl); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 3dac3a48297a..bb72a3b383ea 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -538,6 +538,8 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(D->getLinkageInternal()); Record.AddSourceLocation(D->getLocEnd()); + Record.push_back(D->getODRHash()); + Record.push_back(D->getTemplatedKind()); switch (D->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: @@ -2072,6 +2074,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // LateParsed Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // TemplateKind // This Array slurps the rest of the record. Fortunately we want to encode // (nearly) all the remaining (variable number of) fields in the same way. |