v.g.vassilev updated this revision to Diff 73688.
v.g.vassilev added a comment.
Address some comments and publish current progress.
https://reviews.llvm.org/D24508
Files:
include/clang/AST/Decl.h
lib/AST/Decl.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/SemaType.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Modules/Inputs/PR28752/Subdir1/b.h
test/Modules/Inputs/PR28752/Subdir1/c.h
test/Modules/Inputs/PR28752/Subdir1/module.modulemap
test/Modules/Inputs/PR28752/a.h
test/Modules/Inputs/PR28752/module.modulemap
test/Modules/Inputs/PR28752/vector
test/Modules/Inputs/merge-class-definition-visibility/a.h
test/Modules/Inputs/merge-class-definition-visibility/c.h
test/Modules/merge-class-definition-visibility.cpp
test/Modules/pr28752.cpp
Index: test/Modules/pr28752.cpp
===================================================================
--- /dev/null
+++ test/Modules/pr28752.cpp
@@ -0,0 +1,19 @@
+// 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
+
+#include "a.h"
+#include "Subdir1/c.h"
+#include <vector>
+
+class TClingClassInfo {
+ std::vector<int> fIterStack;
+};
+
+TClingClassInfo *a;
+class TClingBaseClassInfo {
+ TClingBaseClassInfo() { new TClingClassInfo(*a); }
+};
+
+// expected-no-diagnostics
+
Index: test/Modules/merge-class-definition-visibility.cpp
===================================================================
--- test/Modules/merge-class-definition-visibility.cpp
+++ test/Modules/merge-class-definition-visibility.cpp
@@ -1,6 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/merge-class-definition-visibility/modmap \
-// RUN: -I%S/Inputs/merge-class-definition-visibility \
+// RUN: -std=c++1z -I%S/Inputs/merge-class-definition-visibility \
// RUN: -fmodules-cache-path=%t %s -verify \
// RUN: -fmodules-local-submodule-visibility
// expected-no-diagnostics
Index: test/Modules/Inputs/merge-class-definition-visibility/c.h
===================================================================
--- test/Modules/Inputs/merge-class-definition-visibility/c.h
+++ test/Modules/Inputs/merge-class-definition-visibility/c.h
@@ -1 +1,3 @@
struct A;
+
+inline int var_A;
Index: test/Modules/Inputs/merge-class-definition-visibility/a.h
===================================================================
--- test/Modules/Inputs/merge-class-definition-visibility/a.h
+++ test/Modules/Inputs/merge-class-definition-visibility/a.h
@@ -1 +1,3 @@
struct A {};
+
+inline int var_A = 2;
Index: test/Modules/Inputs/PR28752/vector
===================================================================
--- /dev/null
+++ test/Modules/Inputs/PR28752/vector
@@ -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
\ No newline at end of file
Index: test/Modules/Inputs/PR28752/module.modulemap
===================================================================
--- /dev/null
+++ test/Modules/Inputs/PR28752/module.modulemap
@@ -0,0 +1 @@
+module a { header "a.h" export * }
Index: test/Modules/Inputs/PR28752/a.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/PR28752/a.h
@@ -0,0 +1 @@
+#include <vector>
Index: test/Modules/Inputs/PR28752/Subdir1/module.modulemap
===================================================================
--- /dev/null
+++ test/Modules/Inputs/PR28752/Subdir1/module.modulemap
@@ -0,0 +1,5 @@
+module b {
+ module "b.h" { header "b.h" export * }
+ module "c.h" { header "c.h" export * }
+ export *
+}
Index: test/Modules/Inputs/PR28752/Subdir1/b.h
===================================================================
--- /dev/null
+++ test/Modules/Inputs/PR28752/Subdir1/b.h
@@ -0,0 +1 @@
+#include <vector>
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -893,6 +893,7 @@
Record.push_back(D->getStorageClass());
Record.push_back(D->getTSCSpec());
Record.push_back(D->getInitStyle());
+ Record.push_back(D->isThisDeclarationADemotedDefinition());
if (!isa<ParmVarDecl>(D)) {
Record.push_back(D->isExceptionVariable());
Record.push_back(D->isNRVOVariable());
@@ -1000,6 +1001,8 @@
// 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");
@@ -1880,9 +1883,10 @@
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
- Abv->Add(BitCodeAbbrevOp(0)); // StorageClass
- Abv->Add(BitCodeAbbrevOp(0)); // getTSCSpec
- Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(0)); // SClass
+ Abv->Add(BitCodeAbbrevOp(0)); // TSCSpec
+ Abv->Add(BitCodeAbbrevOp(0)); // InitStyle
+ Abv->Add(BitCodeAbbrevOp(0)); // IsThisDeclarationADemotedDefinition
Abv->Add(BitCodeAbbrevOp(0)); // Linkage
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
@@ -1956,9 +1960,10 @@
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc
Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo
// VarDecl
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // StorageClass
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getTSCSpec
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // CXXDirectInitializer
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // 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
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -1216,6 +1216,7 @@
VD->VarDeclBits.SClass = (StorageClass)Record[Idx++];
VD->VarDeclBits.TSCSpec = Record[Idx++];
VD->VarDeclBits.InitStyle = Record[Idx++];
+ VD->VarDeclBits.IsThisDeclarationADemotedDefinition = Record[Idx++];
if (!isa<ParmVarDecl>(VD)) {
VD->NonParmVarDeclBits.ExceptionVar = Record[Idx++];
VD->NonParmVarDeclBits.NRVOVariable = Record[Idx++];
@@ -2321,16 +2322,16 @@
void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase,
RedeclarableResult &Redecl,
DeclID TemplatePatternID) {
- T *D = static_cast<T*>(DBase);
-
// If modules are not available, there is no reason to perform this merge.
if (!Reader.getContext().getLangOpts().Modules)
return;
// If we're not the canonical declaration, we don't need to merge.
if (!DBase->isFirstDecl())
return;
+ T *D = static_cast<T*>(DBase);
+
if (auto *Existing = Redecl.getKnownMergeTarget())
// We already know of an existing declaration we should merge with.
mergeRedeclarable(D, cast<T>(Existing), Redecl, TemplatePatternID);
@@ -2356,7 +2357,6 @@
auto *ExistingPattern = Existing->getTemplatedDecl();
RedeclarableResult Result(DPattern->getCanonicalDecl()->getGlobalID(),
/*MergeWith*/ ExistingPattern, IsKeyDecl);
-
if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) {
// Merge with any existing definition.
// FIXME: This is duplicated in several places. Refactor.
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp
+++ lib/Sema/SemaType.cpp
@@ -6894,6 +6894,10 @@
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");
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4067,6 +4067,10 @@
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.
@@ -4115,47 +4119,38 @@
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;
- else
- Diag(PointOfInstantiation,
- diag::err_explicit_instantiation_undefined_member)
- << 2 << Var->getDeclName() << Var->getDeclContext();
- Diag(PatternDecl->getLocation(),
- diag::note_explicit_instantiation_here);
- if (VarSpec)
- Var->setInvalidDecl();
- } 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)
<< Var;
Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
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.
+ if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Var,
+ /*InstantiatedFromMember*/false,
+ PatternDecl, Def, TSK,
+ /*Complain*/DefinitionRequired))
+ return;
+
// Never instantiate an explicit specialization.
if (TSK == TSK_ExplicitSpecialization)
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -466,10 +466,14 @@
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,6 +490,7 @@
if (!Complain || (PatternDef && PatternDef->isInvalidDecl()))
return true;
+ llvm::Optional<unsigned> Note;
QualType InstantiationTy;
if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
InstantiationTy = Context.getTypeDeclType(TD);
@@ -502,27 +507,40 @@
Diag(PointOfInstantiation,
diag::err_explicit_instantiation_undefined_member)
<< 1 << Instantiation->getDeclName() << Instantiation->getDeclContext();
- } else {
+ Note = diag::note_explicit_instantiation_here;
+ } else if (isa<TagDecl>(Instantiation)) {
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 if (isa<VarDecl>(Instantiation)) {
+ 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)
+ << 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
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -1926,6 +1926,9 @@
//
// 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,35 @@
return Eval->IsICE;
}
+VarDecl *VarDecl::getTemplateInstantiationPattern() const {
+ if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) {
+ if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) {
+ VarDecl *VD = getInstantiatedFromStaticDataMember();
+ while (auto *NewVD = VD->getInstantiatedFromStaticDataMember())
+ VD = NewVD;
+ return VD;
+ }
+ }
+
+ if (VarTemplateDecl *VarTemplate = getDescribedVarTemplate()) {
+
+ while (VarTemplate->getInstantiatedFromMemberTemplate()) {
+ // If we have hit a point where the user provided a specialization of
+ // this template, we're done looking.
+ if (VarTemplate->isMemberSpecialization())
+ break;
+ VarTemplate = VarTemplate->getInstantiatedFromMemberTemplate();
+ }
+
+ assert((!VarTemplate->getTemplatedDecl() ||
+ !isTemplateInstantiation(getTemplateSpecializationKind())) &&
+ "couldn't find pattern for enum instantiation");
+
+ return VarTemplate->getTemplatedDecl();
+ }
+ return nullptr;
+}
+
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -809,8 +809,10 @@
unsigned SClass : 3;
unsigned TSCSpec : 2;
unsigned InitStyle : 2;
+ // FIXME: We need something similar to CXXRecordDecl::DefinitionData.
+ unsigned IsThisDeclarationADemotedDefinition : 1;
};
- enum { NumVarDeclBits = 7 };
+ enum { NumVarDeclBits = 8 };
friend class ASTDeclReader;
friend class StmtIteratorBase;
@@ -1199,6 +1201,22 @@
return static_cast<InitializationStyle>(VarDeclBits.InitStyle);
}
+ /// \brief If this definition should pretend to be a declaration.
+ bool isThisDeclarationADemotedDefinition() const {
+ return VarDeclBits.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 (!isThisDeclarationADemotedDefinition() && "Aleady demoted!");
+ assert (isThisDeclarationADefinition() && "Not a definition!");
+ VarDeclBits.IsThisDeclarationADemotedDefinition = 1;
+ }
+
/// \brief Whether the initializer is a direct-initializer (list or call).
bool isDirectInit() const {
return getInitStyle() != CInit;
@@ -1302,6 +1320,10 @@
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.
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits