r284284 - Reinstate r284008 reverted in r284081, with two fixes:
Vassil Vassilev via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 15 00:35:02 PDT 2016
Thanks!
When calling makeMergedDefinitionVisible shouldn't we get the template
instantiation pattern?
On 14/10/16 23:41, Richard Smith via cfe-commits wrote:
> Author: rsmith
> Date: Fri Oct 14 16:41:24 2016
> New Revision: 284284
>
> URL: http://llvm.org/viewvc/llvm-project?rev=284284&view=rev
> Log:
> 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.
>
> Added:
> cfe/trunk/test/Modules/Inputs/PR28752/
> - copied from r284080, cfe/trunk/test/Modules/Inputs/PR28752/
> cfe/trunk/test/Modules/pr28752.cpp
> - copied, changed from r284080, cfe/trunk/test/Modules/pr28752.cpp
> Modified:
> cfe/trunk/include/clang/AST/Decl.h
> cfe/trunk/include/clang/Sema/Sema.h
> cfe/trunk/lib/AST/Decl.cpp
> cfe/trunk/lib/Sema/SemaDecl.cpp
> cfe/trunk/lib/Sema/SemaTemplate.cpp
> cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> cfe/trunk/lib/Sema/SemaType.cpp
> cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
> cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/b.h
> cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/c.h
>
> Modified: cfe/trunk/include/clang/AST/Decl.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Decl.h (original)
> +++ cfe/trunk/include/clang/AST/Decl.h Fri Oct 14 16:41:24 2016
> @@ -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.
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Fri Oct 14 16:41:24 2016
> @@ -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
>
> Modified: cfe/trunk/lib/AST/Decl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/Decl.cpp (original)
> +++ cfe/trunk/lib/AST/Decl.cpp Fri Oct 14 16:41:24 2016
> @@ -1926,6 +1926,9 @@ VarDecl::isThisDeclarationADefinition(AS
> //
> // 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());
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Oct 14 16:41:24 2016
> @@ -3675,29 +3675,16 @@ void Sema::MergeVarDecl(VarDecl *New, Lo
> }
>
> // 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, Lo
> 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 *Re
> 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
>
> Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Oct 14 16:41:24 2016
> @@ -466,10 +466,14 @@ bool Sema::DiagnoseUninstantiableTemplat
> 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::DiagnoseUninstantiableTemplat
> 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::DiagnoseUninstantiableTemplat
> 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
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Fri Oct 14 16:41:24 2016
> @@ -4068,6 +4068,10 @@ void Sema::InstantiateVariableDefinition
> 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
> 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
> 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)
>
> Modified: cfe/trunk/lib/Sema/SemaType.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaType.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaType.cpp Fri Oct 14 16:41:24 2016
> @@ -6888,6 +6888,10 @@ bool Sema::hasVisibleDefinition(NamedDec
> 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");
>
>
> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Oct 14 16:41:24 2016
> @@ -1216,6 +1216,7 @@ ASTDeclReader::RedeclarableResult ASTDec
> 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++];
> @@ -3069,6 +3070,29 @@ void ASTDeclReader::attachPreviousDeclIm
> 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,
> Decl *Previous, Decl *Canon) {
> FunctionDecl *FD = static_cast<FunctionDecl*>(D);
>
> Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=284284&r1=284283&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Oct 14 16:41:24 2016
> @@ -894,6 +894,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl
> 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(Par
> // 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
>
> Modified: cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/b.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/b.h?rev=284284&r1=284080&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/b.h (original)
> +++ cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/b.h Fri Oct 14 16:41:24 2016
> @@ -1 +1,4 @@
> #include <vector>
> +
> +template<typename T> struct A { static bool b; };
> +template<typename T> bool A<T>::b;
>
> Modified: cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/c.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/c.h?rev=284284&r1=284080&r2=284284&view=diff
> ==============================================================================
> --- cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/c.h (original)
> +++ cfe/trunk/test/Modules/Inputs/PR28752/Subdir1/c.h Fri Oct 14 16:41:24 2016
> @@ -0,0 +1,2 @@
> +template<typename T> struct A { static bool b; };
> +template<typename T> bool A<T>::b;
>
> Copied: cfe/trunk/test/Modules/pr28752.cpp (from r284080, cfe/trunk/test/Modules/pr28752.cpp)
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/pr28752.cpp?p2=cfe/trunk/test/Modules/pr28752.cpp&p1=cfe/trunk/test/Modules/pr28752.cpp&r1=284080&r2=284284&rev=284284&view=diff
> ==============================================================================
> --- cfe/trunk/test/Modules/pr28752.cpp (original)
> +++ cfe/trunk/test/Modules/pr28752.cpp Fri Oct 14 16:41:24 2016
> @@ -1,6 +1,6 @@
> // 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
> +// 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"
> @@ -15,5 +15,8 @@ class TClingBaseClassInfo {
> TClingBaseClassInfo() { new TClingClassInfo(*a); }
> };
>
> +namespace { struct Q; }
> +bool *p = &A<Q>::b;
> +
> // expected-no-diagnostics
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list