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@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits