mirror of https://github.com/microsoft/clang.git
Reinstate r284008 reverted in r284081, with two fixes:
1) Merge and demote variable definitions when we find a redefinition in MergeVarDecls, not only when we find one in AddInitializerToDecl (we only reach the second case if it's the addition of the initializer itself that converts an existing declaration into a definition). 2) When rebuilding a redeclaration chain for a variable, if we merge two definitions together, mark the definitions as merged so the retained definition is made visible whenever the demoted definition would have been. Original commit message (from r283882): [modules] PR28752: Do not instantiate variable declarations which are not visible. Original patch by Vassil Vassilev! Changes listed above are mine. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@284284 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
80ec6606b5
commit
5b36200c3d
|
@ -865,6 +865,11 @@ protected:
|
|||
|
||||
unsigned : NumVarDeclBits;
|
||||
|
||||
// FIXME: We need something similar to CXXRecordDecl::DefinitionData.
|
||||
/// \brief Whether this variable is a definition which was demoted due to
|
||||
/// module merge.
|
||||
unsigned IsThisDeclarationADemotedDefinition : 1;
|
||||
|
||||
/// \brief Whether this variable is the exception variable in a C++ catch
|
||||
/// or an Objective-C @catch statement.
|
||||
unsigned ExceptionVar : 1;
|
||||
|
@ -1198,12 +1203,28 @@ public:
|
|||
InitializationStyle getInitStyle() const {
|
||||
return static_cast<InitializationStyle>(VarDeclBits.InitStyle);
|
||||
}
|
||||
|
||||
/// \brief Whether the initializer is a direct-initializer (list or call).
|
||||
bool isDirectInit() const {
|
||||
return getInitStyle() != CInit;
|
||||
}
|
||||
|
||||
/// \brief If this definition should pretend to be a declaration.
|
||||
bool isThisDeclarationADemotedDefinition() const {
|
||||
return isa<ParmVarDecl>(this) ? false :
|
||||
NonParmVarDeclBits.IsThisDeclarationADemotedDefinition;
|
||||
}
|
||||
|
||||
/// \brief This is a definition which should be demoted to a declaration.
|
||||
///
|
||||
/// In some cases (mostly module merging) we can end up with two visible
|
||||
/// definitions one of which needs to be demoted to a declaration to keep
|
||||
/// the AST invariants.
|
||||
void demoteThisDefinitionToDeclaration() {
|
||||
assert (isThisDeclarationADefinition() && "Not a definition!");
|
||||
assert (!isa<ParmVarDecl>(this) && "Cannot demote ParmVarDecls!");
|
||||
NonParmVarDeclBits.IsThisDeclarationADemotedDefinition = 1;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this variable is the exception variable in a
|
||||
/// C++ catch statememt or an Objective-C \@catch statement.
|
||||
bool isExceptionVariable() const {
|
||||
|
@ -1302,6 +1323,10 @@ public:
|
|||
NonParmVarDeclBits.PreviousDeclInSameBlockScope = Same;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the variable declaration from which this variable could
|
||||
/// be instantiated, if it is an instantiation (rather than a non-template).
|
||||
VarDecl *getTemplateInstantiationPattern() const;
|
||||
|
||||
/// \brief If this variable is an instantiated static data member of a
|
||||
/// class template specialization, returns the templated static data member
|
||||
/// from which it was instantiated.
|
||||
|
|
|
@ -2286,6 +2286,7 @@ public:
|
|||
void MergeVarDecl(VarDecl *New, LookupResult &Previous);
|
||||
void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld);
|
||||
void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old);
|
||||
bool checkVarDeclRedefinition(VarDecl *OldDefn, VarDecl *NewDefn);
|
||||
bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S);
|
||||
|
||||
// AssignmentAction - This is used by all the assignment diagnostic functions
|
||||
|
|
|
@ -1926,6 +1926,9 @@ VarDecl::isThisDeclarationADefinition(ASTContext &C) const {
|
|||
//
|
||||
// FIXME: How do you declare (but not define) a partial specialization of
|
||||
// a static data member template outside the containing class?
|
||||
if (isThisDeclarationADemotedDefinition())
|
||||
return DeclarationOnly;
|
||||
|
||||
if (isStaticDataMember()) {
|
||||
if (isOutOfLine() &&
|
||||
!(getCanonicalDecl()->isInline() &&
|
||||
|
@ -2250,6 +2253,56 @@ bool VarDecl::checkInitIsICE() const {
|
|||
return Eval->IsICE;
|
||||
}
|
||||
|
||||
VarDecl *VarDecl::getTemplateInstantiationPattern() const {
|
||||
// If it's a variable template specialization, find the template or partial
|
||||
// specialization from which it was instantiated.
|
||||
if (auto *VDTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(this)) {
|
||||
auto From = VDTemplSpec->getInstantiatedFrom();
|
||||
if (auto *VTD = From.dyn_cast<VarTemplateDecl *>()) {
|
||||
while (auto *NewVTD = VTD->getInstantiatedFromMemberTemplate()) {
|
||||
if (NewVTD->isMemberSpecialization())
|
||||
break;
|
||||
VTD = NewVTD;
|
||||
}
|
||||
return VTD->getTemplatedDecl()->getDefinition();
|
||||
}
|
||||
if (auto *VTPSD =
|
||||
From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
|
||||
while (auto *NewVTPSD = VTPSD->getInstantiatedFromMember()) {
|
||||
if (NewVTPSD->isMemberSpecialization())
|
||||
break;
|
||||
VTPSD = NewVTPSD;
|
||||
}
|
||||
return VTPSD->getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) {
|
||||
if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) {
|
||||
VarDecl *VD = getInstantiatedFromStaticDataMember();
|
||||
while (auto *NewVD = VD->getInstantiatedFromStaticDataMember())
|
||||
VD = NewVD;
|
||||
return VD->getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) {
|
||||
|
||||
while (VarTemplate->getInstantiatedFromMemberTemplate()) {
|
||||
if (VarTemplate->isMemberSpecialization())
|
||||
break;
|
||||
VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate();
|
||||
}
|
||||
|
||||
assert((!VarTemplate->getTemplatedDecl() ||
|
||||
!isTemplateInstantiation(getTemplateSpecializationKind())) &&
|
||||
"couldn't find pattern for variable instantiation");
|
||||
|
||||
return VarTemplate->getTemplatedDecl();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
|
||||
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
|
||||
return cast<VarDecl>(MSI->getInstantiatedFrom());
|
||||
|
|
|
@ -3675,29 +3675,16 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
}
|
||||
|
||||
// C++ doesn't have tentative definitions, so go right ahead and check here.
|
||||
VarDecl *Def;
|
||||
if (getLangOpts().CPlusPlus &&
|
||||
New->isThisDeclarationADefinition() == VarDecl::Definition &&
|
||||
(Def = Old->getDefinition())) {
|
||||
NamedDecl *Hidden = nullptr;
|
||||
if (!hasVisibleDefinition(Def, &Hidden) &&
|
||||
(New->getFormalLinkage() == InternalLinkage ||
|
||||
New->getDescribedVarTemplate() ||
|
||||
New->getNumTemplateParameterLists() ||
|
||||
New->getDeclContext()->isDependentContext())) {
|
||||
// The previous definition is hidden, and multiple definitions are
|
||||
// permitted (in separate TUs). Form another definition of it.
|
||||
} else if (Old->isStaticDataMember() &&
|
||||
Old->getCanonicalDecl()->isInline() &&
|
||||
Old->getCanonicalDecl()->isConstexpr()) {
|
||||
New->isThisDeclarationADefinition() == VarDecl::Definition) {
|
||||
if (Old->isStaticDataMember() && Old->getCanonicalDecl()->isInline() &&
|
||||
Old->getCanonicalDecl()->isConstexpr()) {
|
||||
// This definition won't be a definition any more once it's been merged.
|
||||
Diag(New->getLocation(),
|
||||
diag::warn_deprecated_redundant_constexpr_static_def);
|
||||
} else {
|
||||
Diag(New->getLocation(), diag::err_redefinition) << New;
|
||||
Diag(Def->getLocation(), diag::note_previous_definition);
|
||||
New->setInvalidDecl();
|
||||
return;
|
||||
} else if (VarDecl *Def = Old->getDefinition()) {
|
||||
if (checkVarDeclRedefinition(Def, New))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3726,6 +3713,32 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
|
|||
New->setImplicitlyInline();
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
if (!hasVisibleDefinition(Old) &&
|
||||
(New->getFormalLinkage() == InternalLinkage ||
|
||||
New->isInline() ||
|
||||
New->getDescribedVarTemplate() ||
|
||||
New->getNumTemplateParameterLists() ||
|
||||
New->getDeclContext()->isDependentContext())) {
|
||||
// The previous definition is hidden, and multiple definitions are
|
||||
// permitted (in separate TUs). Demote this to a declaration.
|
||||
New->demoteThisDefinitionToDeclaration();
|
||||
|
||||
// Make the canonical definition visible.
|
||||
if (auto *OldTD = Old->getDescribedVarTemplate())
|
||||
makeMergedDefinitionVisible(OldTD, New->getLocation());
|
||||
makeMergedDefinitionVisible(Old, New->getLocation());
|
||||
return false;
|
||||
} else {
|
||||
Diag(New->getLocation(), diag::err_redefinition) << New;
|
||||
Diag(Old->getLocation(), diag::note_previous_definition);
|
||||
New->setInvalidDecl();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
|
||||
/// no declarator (e.g. "struct foo;") is parsed.
|
||||
Decl *
|
||||
|
@ -9697,25 +9710,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
VDecl->setInvalidDecl();
|
||||
}
|
||||
|
||||
// If adding the initializer will turn this declaration into a definition,
|
||||
// and we already have a definition for this variable, diagnose or otherwise
|
||||
// handle the situation.
|
||||
VarDecl *Def;
|
||||
if ((Def = VDecl->getDefinition()) && Def != VDecl &&
|
||||
(!VDecl->isStaticDataMember() || VDecl->isOutOfLine())) {
|
||||
NamedDecl *Hidden = nullptr;
|
||||
if (!hasVisibleDefinition(Def, &Hidden) &&
|
||||
(VDecl->getFormalLinkage() == InternalLinkage ||
|
||||
VDecl->getDescribedVarTemplate() ||
|
||||
VDecl->getNumTemplateParameterLists() ||
|
||||
VDecl->getDeclContext()->isDependentContext())) {
|
||||
// The previous definition is hidden, and multiple definitions are
|
||||
// permitted (in separate TUs). Form another definition of it.
|
||||
} else {
|
||||
Diag(VDecl->getLocation(), diag::err_redefinition)
|
||||
<< VDecl->getDeclName();
|
||||
Diag(Def->getLocation(), diag::note_previous_definition);
|
||||
VDecl->setInvalidDecl();
|
||||
return;
|
||||
}
|
||||
}
|
||||
(!VDecl->isStaticDataMember() || VDecl->isOutOfLine()) &&
|
||||
!VDecl->isThisDeclarationADemotedDefinition() &&
|
||||
checkVarDeclRedefinition(Def, VDecl))
|
||||
return;
|
||||
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
// C++ [class.static.data]p4
|
||||
|
|
|
@ -466,10 +466,14 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
|
|||
const NamedDecl *PatternDef,
|
||||
TemplateSpecializationKind TSK,
|
||||
bool Complain /*= true*/) {
|
||||
assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation));
|
||||
assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation) ||
|
||||
isa<VarDecl>(Instantiation));
|
||||
|
||||
if (PatternDef && (isa<FunctionDecl>(PatternDef)
|
||||
|| !cast<TagDecl>(PatternDef)->isBeingDefined())) {
|
||||
bool IsEntityBeingDefined = false;
|
||||
if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(PatternDef))
|
||||
IsEntityBeingDefined = TD->isBeingDefined();
|
||||
|
||||
if (PatternDef && !IsEntityBeingDefined) {
|
||||
NamedDecl *SuggestedDef = nullptr;
|
||||
if (!hasVisibleDefinition(const_cast<NamedDecl*>(PatternDef), &SuggestedDef,
|
||||
/*OnlyNeedComplete*/false)) {
|
||||
|
@ -486,13 +490,14 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
|
|||
if (!Complain || (PatternDef && PatternDef->isInvalidDecl()))
|
||||
return true;
|
||||
|
||||
llvm::Optional<unsigned> Note;
|
||||
QualType InstantiationTy;
|
||||
if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
|
||||
InstantiationTy = Context.getTypeDeclType(TD);
|
||||
if (PatternDef) {
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_template_instantiate_within_definition)
|
||||
<< (TSK != TSK_ImplicitInstantiation)
|
||||
<< /*implicit|explicit*/(TSK != TSK_ImplicitInstantiation)
|
||||
<< InstantiationTy;
|
||||
// Not much point in noting the template declaration here, since
|
||||
// we're lexically inside it.
|
||||
|
@ -501,28 +506,44 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
|
|||
if (isa<FunctionDecl>(Instantiation)) {
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_explicit_instantiation_undefined_member)
|
||||
<< 1 << Instantiation->getDeclName() << Instantiation->getDeclContext();
|
||||
<< /*member function*/ 1 << Instantiation->getDeclName()
|
||||
<< Instantiation->getDeclContext();
|
||||
Note = diag::note_explicit_instantiation_here;
|
||||
} else {
|
||||
assert(isa<TagDecl>(Instantiation) && "Must be a TagDecl!");
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_implicit_instantiate_member_undefined)
|
||||
<< InstantiationTy;
|
||||
Note = diag::note_member_declared_at;
|
||||
}
|
||||
Diag(Pattern->getLocation(), isa<FunctionDecl>(Instantiation)
|
||||
? diag::note_explicit_instantiation_here
|
||||
: diag::note_member_declared_at);
|
||||
} else {
|
||||
if (isa<FunctionDecl>(Instantiation))
|
||||
if (isa<FunctionDecl>(Instantiation)) {
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_explicit_instantiation_undefined_func_template)
|
||||
<< Pattern;
|
||||
else
|
||||
Note = diag::note_explicit_instantiation_here;
|
||||
} else if (isa<TagDecl>(Instantiation)) {
|
||||
Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
|
||||
<< (TSK != TSK_ImplicitInstantiation)
|
||||
<< InstantiationTy;
|
||||
Diag(Pattern->getLocation(), isa<FunctionDecl>(Instantiation)
|
||||
? diag::note_explicit_instantiation_here
|
||||
: diag::note_template_decl_here);
|
||||
Note = diag::note_template_decl_here;
|
||||
} else {
|
||||
assert(isa<VarDecl>(Instantiation) && "Must be a VarDecl!");
|
||||
if (isa<VarTemplateSpecializationDecl>(Instantiation)) {
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_explicit_instantiation_undefined_var_template)
|
||||
<< Instantiation;
|
||||
Instantiation->setInvalidDecl();
|
||||
} else
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_explicit_instantiation_undefined_member)
|
||||
<< /*static data member*/ 2 << Instantiation->getDeclName()
|
||||
<< Instantiation->getDeclContext();
|
||||
Note = diag::note_explicit_instantiation_here;
|
||||
}
|
||||
}
|
||||
if (Note) // Diagnostics were emitted.
|
||||
Diag(Pattern->getLocation(), Note.getValue());
|
||||
|
||||
// In general, Instantiation isn't marked invalid to get more than one
|
||||
// error for multiple undefined instantiations. But the code that does
|
||||
|
|
|
@ -4068,6 +4068,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
|||
PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(),
|
||||
"instantiating variable initializer");
|
||||
|
||||
// The instantiation is visible here, even if it was first declared in an
|
||||
// unimported module.
|
||||
Var->setHidden(false);
|
||||
|
||||
// If we're performing recursive template instantiation, create our own
|
||||
// queue of pending implicit instantiations that we will instantiate
|
||||
// later, while we're still within our own instantiation context.
|
||||
|
@ -4116,33 +4120,17 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
|||
Def = PatternDecl->getDefinition();
|
||||
}
|
||||
|
||||
// FIXME: Check that the definition is visible before trying to instantiate
|
||||
// it. This requires us to track the instantiation stack in order to know
|
||||
// which definitions should be visible.
|
||||
TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
|
||||
|
||||
// If we don't have a definition of the variable template, we won't perform
|
||||
// any instantiation. Rather, we rely on the user to instantiate this
|
||||
// definition (or provide a specialization for it) in another translation
|
||||
// unit.
|
||||
if (!Def) {
|
||||
if (DefinitionRequired) {
|
||||
if (VarSpec) {
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_explicit_instantiation_undefined_var_template) << Var;
|
||||
Var->setInvalidDecl();
|
||||
}
|
||||
else
|
||||
Diag(PointOfInstantiation,
|
||||
diag::err_explicit_instantiation_undefined_member)
|
||||
<< 2 << Var->getDeclName() << Var->getDeclContext();
|
||||
Diag(PatternDecl->getLocation(),
|
||||
diag::note_explicit_instantiation_here);
|
||||
} else if (Var->getTemplateSpecializationKind()
|
||||
== TSK_ExplicitInstantiationDefinition) {
|
||||
if (!Def && !DefinitionRequired) {
|
||||
if (TSK == TSK_ExplicitInstantiationDefinition) {
|
||||
PendingInstantiations.push_back(
|
||||
std::make_pair(Var, PointOfInstantiation));
|
||||
} else if (Var->getTemplateSpecializationKind()
|
||||
== TSK_ImplicitInstantiation) {
|
||||
} else if (TSK == TSK_ImplicitInstantiation) {
|
||||
// Warn about missing definition at the end of translation unit.
|
||||
if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {
|
||||
Diag(PointOfInstantiation, diag::warn_var_template_missing)
|
||||
|
@ -4151,12 +4139,20 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
|
|||
if (getLangOpts().CPlusPlus11)
|
||||
Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
|
||||
// FIXME: We need to track the instantiation stack in order to know which
|
||||
// definitions should be visible within this instantiation.
|
||||
// FIXME: Produce diagnostics when Var->getInstantiatedFromStaticDataMember().
|
||||
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Var,
|
||||
/*InstantiatedFromMember*/false,
|
||||
PatternDecl, Def, TSK,
|
||||
/*Complain*/DefinitionRequired))
|
||||
return;
|
||||
|
||||
|
||||
// Never instantiate an explicit specialization.
|
||||
if (TSK == TSK_ExplicitSpecialization)
|
||||
|
|
|
@ -6888,6 +6888,10 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
|
|||
if (auto *Pattern = FD->getTemplateInstantiationPattern())
|
||||
FD = Pattern;
|
||||
D = FD->getDefinition();
|
||||
} else if (auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
if (auto *Pattern = VD->getTemplateInstantiationPattern())
|
||||
VD = Pattern;
|
||||
D = VD->getDefinition();
|
||||
}
|
||||
assert(D && "missing definition for pattern of instantiated definition");
|
||||
|
||||
|
|
|
@ -1216,6 +1216,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
|
|||
VD->VarDeclBits.TSCSpec = Record[Idx++];
|
||||
VD->VarDeclBits.InitStyle = Record[Idx++];
|
||||
if (!isa<ParmVarDecl>(VD)) {
|
||||
VD->NonParmVarDeclBits.IsThisDeclarationADemotedDefinition = Record[Idx++];
|
||||
VD->NonParmVarDeclBits.ExceptionVar = Record[Idx++];
|
||||
VD->NonParmVarDeclBits.NRVOVariable = Record[Idx++];
|
||||
VD->NonParmVarDeclBits.CXXForRangeDecl = Record[Idx++];
|
||||
|
@ -3067,6 +3068,29 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
|
|||
}
|
||||
|
||||
namespace clang {
|
||||
template<>
|
||||
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
|
||||
Redeclarable<VarDecl> *D,
|
||||
Decl *Previous, Decl *Canon) {
|
||||
VarDecl *VD = static_cast<VarDecl*>(D);
|
||||
VarDecl *PrevVD = cast<VarDecl>(Previous);
|
||||
D->RedeclLink.setPrevious(PrevVD);
|
||||
D->First = PrevVD->First;
|
||||
|
||||
// We should keep at most one definition on the chain.
|
||||
// FIXME: Cache the definition once we've found it. Building a chain with
|
||||
// N definitions currently takes O(N^2) time here.
|
||||
if (VD->isThisDeclarationADefinition() == VarDecl::Definition) {
|
||||
for (VarDecl *CurD = PrevVD; CurD; CurD = CurD->getPreviousDecl()) {
|
||||
if (CurD->isThisDeclarationADefinition() == VarDecl::Definition) {
|
||||
Reader.mergeDefinitionVisibility(CurD, VD);
|
||||
VD->demoteThisDefinitionToDeclaration();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
|
||||
Redeclarable<FunctionDecl> *D,
|
||||
|
|
|
@ -894,6 +894,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
|
|||
Record.push_back(D->getTSCSpec());
|
||||
Record.push_back(D->getInitStyle());
|
||||
if (!isa<ParmVarDecl>(D)) {
|
||||
Record.push_back(D->isThisDeclarationADemotedDefinition());
|
||||
Record.push_back(D->isExceptionVariable());
|
||||
Record.push_back(D->isNRVOVariable());
|
||||
Record.push_back(D->isCXXForRangeDecl());
|
||||
|
@ -998,6 +999,8 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
|
|||
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
|
||||
// just us assuming it.
|
||||
assert(!D->getTSCSpec() && "PARM_VAR_DECL can't use TLS");
|
||||
assert(!D->isThisDeclarationADemotedDefinition()
|
||||
&& "PARM_VAR_DECL can't be demoted definition.");
|
||||
assert(D->getAccess() == AS_none && "PARM_VAR_DECL can't be public/private");
|
||||
assert(!D->isExceptionVariable() && "PARM_VAR_DECL can't be exception var");
|
||||
assert(D->getPreviousDecl() == nullptr && "PARM_VAR_DECL can't be redecl");
|
||||
|
@ -1957,6 +1960,7 @@ void ASTWriter::WriteDeclAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // SClass
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // TSCSpec
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // InitStyle
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsThisDeclarationADemotedDefinition
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isExceptionVariable
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable
|
||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
#include <vector>
|
||||
|
||||
template<typename T> struct A { static bool b; };
|
||||
template<typename T> bool A<T>::b;
|
|
@ -0,0 +1,2 @@
|
|||
template<typename T> struct A { static bool b; };
|
||||
template<typename T> bool A<T>::b;
|
|
@ -0,0 +1,5 @@
|
|||
module b {
|
||||
module "b.h" { header "b.h" export * }
|
||||
module "c.h" { header "c.h" export * }
|
||||
export *
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#include <vector>
|
|
@ -0,0 +1 @@
|
|||
module a { header "a.h" export * }
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef VECTOR
|
||||
#define VECTOR
|
||||
template <bool, typename> struct B;
|
||||
template <typename _Tp> struct B<true, _Tp> { typedef _Tp type; };
|
||||
namespace std {
|
||||
template <typename> struct D {
|
||||
|
||||
template <typename _Alloc2> struct F {
|
||||
static const bool value = 0;
|
||||
};
|
||||
|
||||
template <typename _Alloc2>
|
||||
typename B<F<_Alloc2>::value, _Alloc2>::type _S_select(_Alloc2);
|
||||
template <typename _Alloc2>
|
||||
static
|
||||
typename B<!F<_Alloc2>::value, _Alloc2>::type _S_select(_Alloc2);
|
||||
};
|
||||
template <typename _Alloc>
|
||||
template <typename _Alloc2>
|
||||
const bool D<_Alloc>::F<_Alloc2>::value;
|
||||
|
||||
template <typename> class vector {
|
||||
public:
|
||||
vector(int);
|
||||
vector(vector &) : vector(D<bool>::_S_select((bool)0)) {}
|
||||
};
|
||||
}
|
||||
#endif // VECTOR
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -std=c++11 -nostdsysteminc -I%S/Inputs/PR28752 -verify %s
|
||||
// RUN: %clang_cc1 -std=c++11 -nostdsysteminc -fmodules -fmodule-map-file=%S/Inputs/PR28752/Subdir1/module.modulemap -fmodule-map-file=%S/Inputs/PR28752/module.modulemap -fmodules-cache-path=%t -I%S/Inputs/PR28752 -I%S/Inputs/PR28752/Subdir1 -verify %s -fmodules-local-submodule-visibility
|
||||
|
||||
#include "a.h"
|
||||
#include "Subdir1/c.h"
|
||||
#include <vector>
|
||||
|
||||
class TClingClassInfo {
|
||||
std::vector<int> fIterStack;
|
||||
};
|
||||
|
||||
TClingClassInfo *a;
|
||||
class TClingBaseClassInfo {
|
||||
TClingBaseClassInfo() { new TClingClassInfo(*a); }
|
||||
};
|
||||
|
||||
namespace { struct Q; }
|
||||
bool *p = &A<Q>::b;
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
Loading…
Reference in New Issue