Diag(New->getLocation(), diag::err_redefinition_variably_modified_typedef)
<< Kind << NewType;
if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
New->setInvalidDecl();
return true;
}
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
<< Kind << NewType << OldType;
if (Old->getLocation().isValid())
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
New->setInvalidDecl();
return true;
}
NamedDecl *OldD = OldDecls.getRepresentativeDecl();
if (OldD->getLocation().isValid())
- Diag(OldD->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(OldD->getLocation(), New->getLocation());
return New->setInvalidDecl();
}
Diag(New->getLocation(), diag::err_redefinition)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
return New->setInvalidDecl();
}
Diag(New->getLocation(), diag::ext_redefinition_of_typedef)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
}
/// DeclhasAttr - returns true if decl Declaration already has the target
? diag::err_alias_after_tentative
: diag::err_redefinition;
S.Diag(VD->getLocation(), Diag) << VD->getDeclName();
- S.Diag(Def->getLocation(), diag::note_previous_definition);
+ if (Diag == diag::err_redefinition)
+ S.notePreviousDefinition(Def->getLocation(), VD->getLocation());
+ else
+ S.Diag(Def->getLocation(), diag::note_previous_definition);
VD->setInvalidDecl();
}
++I;
} else {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
- Diag(OldD->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(OldD->getLocation(), New->getLocation());
return true;
}
}
!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
New->dropAttr<InternalLinkageAttr>();
}
}
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
- << New->getDeclName();
- Diag(Previous.getRepresentativeDecl()->getLocation(),
- diag::note_previous_definition);
+ << New->getDeclName();
+ notePreviousDefinition(Previous.getRepresentativeDecl()->getLocation(),
+ New->getLocation());
return New->setInvalidDecl();
}
Old->getStorageClass() == SC_None &&
!Old->hasAttr<WeakImportAttr>()) {
Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
// Remove weak_import attribute on new declaration.
New->dropAttr<WeakImportAttr>();
}
!Old->hasAttr<InternalLinkageAttr>()) {
Diag(New->getLocation(), diag::err_internal_linkage_redeclaration)
<< New->getDeclName();
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
New->dropAttr<InternalLinkageAttr>();
}
New->setImplicitlyInline();
}
+void Sema::notePreviousDefinition(SourceLocation Old, SourceLocation New) {
+ SourceManager &SrcMgr = getSourceManager();
+ auto FNewDecLoc = SrcMgr.getDecomposedLoc(New);
+ auto FOldDecLoc = SrcMgr.getDecomposedLoc(Old);
+ auto *FNew = SrcMgr.getFileEntryForID(FNewDecLoc.first);
+ auto *FOld = SrcMgr.getFileEntryForID(FOldDecLoc.first);
+ auto &HSI = PP.getHeaderSearchInfo();
+ StringRef HdrFilename = SrcMgr.getFilename(SrcMgr.getSpellingLoc(Old));
+
+ auto noteFromModuleOrInclude = [&](SourceLocation &Loc,
+ SourceLocation &IncLoc) -> bool {
+ Module *Mod = nullptr;
+ // Redefinition errors with modules are common with non modular mapped
+ // headers, example: a non-modular header H in module A that also gets
+ // included directly in a TU. Pointing twice to the same header/definition
+ // is confusing, try to get better diagnostics when modules is on.
+ if (getLangOpts().Modules) {
+ auto ModLoc = SrcMgr.getModuleImportLoc(Old);
+ if (!ModLoc.first.isInvalid())
+ Mod = HSI.getModuleMap().inferModuleFromLocation(
+ FullSourceLoc(Loc, SrcMgr));
+ }
+
+ if (IncLoc.isValid()) {
+ if (Mod) {
+ Diag(IncLoc, diag::note_redefinition_modules_same_file)
+ << HdrFilename.str() << Mod->getFullModuleName();
+ if (!Mod->DefinitionLoc.isInvalid())
+ Diag(Mod->DefinitionLoc, diag::note_defined_here)
+ << Mod->getFullModuleName();
+ } else {
+ Diag(IncLoc, diag::note_redefinition_include_same_file)
+ << HdrFilename.str();
+ }
+ return true;
+ }
+
+ return false;
+ };
+
+ // Is it the same file and same offset? Provide more information on why
+ // this leads to a redefinition error.
+ bool EmittedDiag = false;
+ if (FNew == FOld && FNewDecLoc.second == FOldDecLoc.second) {
+ SourceLocation OldIncLoc = SrcMgr.getIncludeLoc(FOldDecLoc.first);
+ SourceLocation NewIncLoc = SrcMgr.getIncludeLoc(FNewDecLoc.first);
+ EmittedDiag = noteFromModuleOrInclude(Old, OldIncLoc);
+ EmittedDiag |= noteFromModuleOrInclude(New, NewIncLoc);
+
+ // If the header has no guards, emit a note suggesting one.
+ if (FOld && !HSI.isFileMultipleIncludeGuarded(FOld))
+ Diag(Old, diag::note_use_ifdef_guards);
+
+ if (EmittedDiag)
+ return;
+ }
+
+ // Redefinition coming from different files or couldn't do better above.
+ Diag(Old, diag::note_previous_definition);
+}
+
/// We've just determined that \p Old and \p New both appear to be definitions
/// of the same variable. Either diagnose or fix the problem.
bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) {
return false;
} else {
Diag(New->getLocation(), diag::err_redefinition) << New;
- Diag(Old->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Old->getLocation(), New->getLocation());
New->setInvalidDecl();
return true;
}
Diag(NameLoc, diag::warn_redefinition_in_param_list) << Name;
else
Diag(NameLoc, diag::err_redefinition) << Name;
- Diag(Def->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(Def->getLocation(),
+ NameLoc.isValid() ? NameLoc : KWLoc);
// If this is a redefinition, recover by making this
// struct be anonymous, which will make any later
// references get the previous definition.
// The tag name clashes with something else in the target scope,
// issue an error and recover by making this tag be anonymous.
Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(PrevDecl->getLocation(), NameLoc);
Name = nullptr;
Invalid = true;
}
Diag(IdLoc, diag::err_redefinition_of_enumerator) << Id;
else
Diag(IdLoc, diag::err_redefinition) << Id;
- Diag(PrevDecl->getLocation(), diag::note_previous_definition);
+ notePreviousDefinition(PrevDecl->getLocation(), IdLoc);
return nullptr;
}
}