Merge remote-tracking branch 'origin/swift-3.1-branch' into stable
* origin/swift-3.1-branch:
Revert "Revert "[index] Handle properly C++14's template variables.""
[modules] Do not report missing definitions of demoted constexpr variable templates.
Reinstate r284008 reverted in r284081, with two fixes:
[modules] Allow VarDecls with initializers to use special var abbrev.
Revert accidentally checked in change in r281315.
Simplify. NFC.
Add a couple of test files missed in r281258.
[modules] When we merge two definitions of a function, mark the retained definition as visible in the discarded definition's module, as we do for other kinds of definition.
PR12298 et al: don't recursively instantiate a template specialization from within the instantiation of that same specialization. This could previously happen for eagerly-instantiated function templates, variable templates, exception specifications, default arguments, and a handful of other cases.
Fix regression introduced by r279164: only pass definitions as the PatternDef to DiagnoseUninstantiableTemplate, teach hasVisibleDefinition to correctly determine whether a function definition is visible, and mark both the function and the template as visible when merging function template definitions to provide hasVisibleDefinition with the relevant information.
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 77bbdb2..2474637 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -865,6 +865,11 @@
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 @@
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 @@
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.
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 8671d95..2af95c0 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -43,6 +43,8 @@
typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*,
TemplateTemplateParmDecl*> TemplateParameter;
+NamedDecl *getAsNamedDecl(TemplateParameter P);
+
/// \brief Stores a list of template parameters for a TemplateDecl and its
/// derived classes.
class TemplateParameterList final
@@ -2937,6 +2939,14 @@
friend class ASTDeclWriter;
};
+inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
+ if (auto *PD = P.dyn_cast<TemplateTypeParmDecl*>())
+ return PD;
+ if (auto *PD = P.dyn_cast<NonTypeTemplateParmDecl*>())
+ return PD;
+ return P.get<TemplateTemplateParmDecl*>();
+}
+
} /* end of namespace clang */
#endif
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index d373e3c..a72bd8e 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7083,6 +7083,10 @@
def err_in_class_initializer_not_yet_parsed_outer_class
: Error<"cannot use defaulted default constructor of %0 within "
"%1 outside of member functions because %2 has an initializer">;
+def err_in_class_initializer_cycle
+ : Error<"default member initializer for %0 uses itself">;
+def err_exception_spec_cycle
+ : Error<"exception specification of %0 uses itself">;
def ext_in_class_initializer_non_constant : Extension<
"in-class initializer for static data member is not a constant expression; "
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 544af8f..25e8a9d 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -18,6 +18,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Availability.h"
#include "clang/AST/DeclarationName.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExternalASTSource.h"
@@ -2251,6 +2252,7 @@
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
@@ -6691,10 +6693,10 @@
TemplateInstantiation,
/// We are instantiating a default argument for a template
- /// parameter. The Entity is the template, and
- /// TemplateArgs/NumTemplateArguments provides the template
- /// arguments as specified.
- /// FIXME: Use a TemplateArgumentList
+ /// parameter. The Entity is the template parameter whose argument is
+ /// being instantiated, the Template is the template, and the
+ /// TemplateArgs/NumTemplateArguments provide the template arguments as
+ /// specified.
DefaultTemplateArgumentInstantiation,
/// We are instantiating a default argument for a function.
@@ -6809,6 +6811,9 @@
SmallVector<ActiveTemplateInstantiation, 16>
ActiveTemplateInstantiations;
+ /// Specializations whose definitions are currently being instantiated.
+ llvm::DenseSet<std::pair<Decl *, unsigned>> InstantiatingSpecializations;
+
/// \brief Extra modules inspected when performing a lookup during a template
/// instantiation. Computed lazily.
SmallVector<Module*, 16> ActiveTemplateInstantiationLookupModules;
@@ -6915,12 +6920,12 @@
/// \brief Note that we are instantiating a default argument in a
/// template-id.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
- TemplateDecl *Template,
+ TemplateParameter Param, TemplateDecl *Template,
ArrayRef<TemplateArgument> TemplateArgs,
SourceRange InstantiationRange = SourceRange());
- /// \brief Note that we are instantiating a default argument in a
- /// template-id.
+ /// \brief Note that we are substituting either explicitly-specified or
+ /// deduced template arguments during function template argument deduction.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
FunctionTemplateDecl *FunctionTemplate,
ArrayRef<TemplateArgument> TemplateArgs,
@@ -6987,9 +6992,14 @@
/// recursive template instantiations.
bool isInvalid() const { return Invalid; }
+ /// \brief Determine whether we are already instantiating this
+ /// specialization in some surrounding active instantiation.
+ bool isAlreadyInstantiating() const { return AlreadyInstantiating; }
+
private:
Sema &SemaRef;
bool Invalid;
+ bool AlreadyInstantiating;
bool SavedInNonInstantiationSFINAEContext;
bool CheckInstantiationDepth(SourceLocation PointOfInstantiation,
SourceRange InstantiationRange);
diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h
index 943765d..348189b 100644
--- a/include/clang/Serialization/ASTReader.h
+++ b/include/clang/Serialization/ASTReader.h
@@ -1405,6 +1405,10 @@
/// \brief Make the names within this set of hidden names visible.
void makeNamesVisible(const HiddenNames &Names, Module *Owner);
+ /// \brief Note that MergedDef is a redefinition of the canonical definition
+ /// Def, so Def should be visible whenever MergedDef is.
+ void mergeDefinitionVisibility(NamedDecl *Def, NamedDecl *MergedDef);
+
/// \brief Take the AST callbacks listener.
std::unique_ptr<ASTReaderListener> takeListener() {
return std::move(Listener);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index cfdd557..44564c1 100644
--- a/lib/AST/Decl.cpp
+++ b/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,56 @@
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());
diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp
index d98d7c0..4126bb6 100644
--- a/lib/Index/IndexSymbol.cpp
+++ b/lib/Index/IndexSymbol.cpp
@@ -91,6 +91,25 @@
Info.SubKinds |= (unsigned)SymbolSubKind::TemplateSpecialization;
}
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ Info.Kind = SymbolKind::Variable;
+ if (isa<CXXRecordDecl>(D->getDeclContext())) {
+ Info.Kind = SymbolKind::StaticProperty;
+ Info.Lang = SymbolLanguage::CXX;
+ }
+ if (isa<VarTemplatePartialSpecializationDecl>(D)) {
+ Info.Lang = SymbolLanguage::CXX;
+ Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
+ Info.SubKinds |= (unsigned)SymbolSubKind::TemplatePartialSpecialization;
+ } else if (isa<VarTemplateSpecializationDecl>(D)) {
+ Info.Lang = SymbolLanguage::CXX;
+ Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
+ Info.SubKinds |= (unsigned)SymbolSubKind::TemplateSpecialization;
+ } else if (VD->getDescribedVarTemplate()) {
+ Info.Lang = SymbolLanguage::CXX;
+ Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
+ }
+
} else {
switch (D->getKind()) {
case Decl::Import:
@@ -101,16 +120,6 @@
case Decl::Function:
Info.Kind = SymbolKind::Function;
break;
- case Decl::ParmVar:
- Info.Kind = SymbolKind::Variable;
- break;
- case Decl::Var:
- Info.Kind = SymbolKind::Variable;
- if (isa<CXXRecordDecl>(D->getDeclContext())) {
- Info.Kind = SymbolKind::StaticProperty;
- Info.Lang = SymbolLanguage::CXX;
- }
- break;
case Decl::Field:
Info.Kind = SymbolKind::Field;
if (const CXXRecordDecl *
diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp
index 21869d8..e623a49 100644
--- a/lib/Index/IndexingContext.cpp
+++ b/lib/Index/IndexingContext.cpp
@@ -130,9 +130,10 @@
if (const ClassTemplateSpecializationDecl *
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
TKind = SD->getSpecializationKind();
- }
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
TKind = FD->getTemplateSpecializationKind();
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ TKind = VD->getTemplateSpecializationKind();
}
switch (TKind) {
case TSK_Undeclared:
@@ -164,9 +165,10 @@
if (const ClassTemplateSpecializationDecl *
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
return SD->getTemplateInstantiationPattern();
- }
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
return FD->getTemplateInstantiationPattern();
+ } else if (auto *VD = dyn_cast<VarDecl>(D)) {
+ return VD->getTemplateInstantiationPattern();
}
return nullptr;
}
diff --git a/lib/Index/USRGeneration.cpp b/lib/Index/USRGeneration.cpp
index bec777d..58f61c3 100644
--- a/lib/Index/USRGeneration.cpp
+++ b/lib/Index/USRGeneration.cpp
@@ -286,6 +286,15 @@
VisitDeclContext(D->getDeclContext());
+ if (VarTemplateDecl *VarTmpl = D->getDescribedVarTemplate()) {
+ Out << "@VT";
+ VisitTemplateParameterList(VarTmpl->getTemplateParameters());
+ } else if (const VarTemplatePartialSpecializationDecl *PartialSpec
+ = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) {
+ Out << "@VP";
+ VisitTemplateParameterList(PartialSpec->getTemplateParameters());
+ }
+
// Variables always have simple names.
StringRef s = D->getName();
@@ -297,6 +306,17 @@
IgnoreResults = true;
else
Out << '@' << s;
+
+ // For a template specialization, mangle the template arguments.
+ if (const VarTemplateSpecializationDecl *Spec
+ = dyn_cast<VarTemplateSpecializationDecl>(D)) {
+ const TemplateArgumentList &Args = Spec->getTemplateInstantiationArgs();
+ Out << '>';
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ Out << '#';
+ VisitTemplateArgument(Args.get(I));
+ }
+ }
}
void USRGenerator::VisitNonTypeTemplateParmDecl(
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 1b9ff61..cae1c19 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3667,29 +3667,16 @@
}
// 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;
}
}
@@ -3718,6 +3705,32 @@
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 *
@@ -9654,24 +9667,15 @@
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) {
- 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;
- }
- }
+ if ((Def = VDecl->getDefinition()) && Def != VDecl &&
+ (!VDecl->isStaticDataMember() || VDecl->isOutOfLine()) &&
+ !VDecl->isThisDeclarationADemotedDefinition() &&
+ checkVarDeclRedefinition(Def, VDecl))
+ return;
if (getLangOpts().CPlusPlus) {
// C++ [class.static.data]p4
@@ -10060,7 +10064,11 @@
// C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to
// the definition of a variable [...] or the declaration of a static data
// member.
- if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) {
+ if (Var->isConstexpr() && !Var->isThisDeclarationADefinition() &&
+ !Var->isThisDeclarationADemotedDefinition()) {
+ assert((!Var->isThisDeclarationADemotedDefinition() ||
+ getLangOpts().Modules) &&
+ "Demoting decls is only in the contest of modules!");
if (Var->isStaticDataMember()) {
// C++1z removes the relevant rule; the in-class declaration is always
// a definition there.
@@ -11283,9 +11291,8 @@
SkipBody->ShouldSkip = true;
if (auto *TD = Definition->getDescribedFunctionTemplate())
makeMergedDefinitionVisible(TD, FD->getLocation());
- else
- makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition),
- FD->getLocation());
+ makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition),
+ FD->getLocation());
return;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index ef46f8f..c66cc3a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4546,6 +4546,11 @@
MutiLevelArgList.getInnermost());
if (Inst.isInvalid())
return ExprError();
+ if (Inst.isAlreadyInstantiating()) {
+ Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD;
+ Param->setInvalidDecl();
+ return ExprError();
+ }
ExprResult Result;
{
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 84d009f..436a19a 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/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)) {
@@ -483,33 +487,63 @@
return false;
}
+ if (!Complain || (PatternDef && PatternDef->isInvalidDecl()))
+ return true;
+ llvm::Optional<unsigned> Note;
QualType InstantiationTy;
if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation))
InstantiationTy = Context.getTypeDeclType(TD);
- else
- InstantiationTy = cast<FunctionDecl>(Instantiation)->getType();
- if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
- // Say nothing
- } else if (PatternDef) {
+ 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.
Instantiation->setInvalidDecl();
} else if (InstantiatedFromMember) {
- Diag(PointOfInstantiation,
- diag::err_implicit_instantiate_member_undefined)
- << InstantiationTy;
- Diag(Pattern->getLocation(), diag::note_member_declared_at);
+ if (isa<FunctionDecl>(Instantiation)) {
+ Diag(PointOfInstantiation,
+ diag::err_explicit_instantiation_undefined_member)
+ << /*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;
+ }
} else {
- Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
- << (TSK != TSK_ImplicitInstantiation)
- << InstantiationTy;
- Diag(Pattern->getLocation(), diag::note_template_decl_here);
+ if (isa<FunctionDecl>(Instantiation)) {
+ Diag(PointOfInstantiation,
+ diag::err_explicit_instantiation_undefined_func_template)
+ << Pattern;
+ Note = diag::note_explicit_instantiation_here;
+ } else if (isa<TagDecl>(Instantiation)) {
+ Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
+ << (TSK != TSK_ImplicitInstantiation)
+ << InstantiationTy;
+ 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
@@ -3317,7 +3351,7 @@
// on the previously-computed template arguments.
if (ArgType->getType()->isDependentType()) {
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Template, Converted,
+ Param, Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return nullptr;
@@ -3369,7 +3403,7 @@
NonTypeTemplateParmDecl *Param,
SmallVectorImpl<TemplateArgument> &Converted) {
Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc,
- Template, Converted,
+ Param, Template, Converted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return ExprError();
@@ -3420,8 +3454,9 @@
TemplateTemplateParmDecl *Param,
SmallVectorImpl<TemplateArgument> &Converted,
NestedNameSpecifierLoc &QualifierLoc) {
- Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted,
- SourceRange(TemplateLoc, RAngleLoc));
+ Sema::InstantiatingTemplate Inst(
+ SemaRef, TemplateLoc, TemplateParameter(Param), Template, Converted,
+ SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
return TemplateName();
@@ -4042,7 +4077,9 @@
}
// Introduce an instantiation record that describes where we are using
- // the default template argument.
+ // the default template argument. We're not actually instantiating a
+ // template here, we just create this object to put a note into the
+ // context stack.
InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted,
SourceRange(TemplateLoc, RAngleLoc));
if (Inst.isInvalid())
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index e7b221d..8dcd4a0 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -228,6 +228,10 @@
Inst.NumTemplateArgs = TemplateArgs.size();
Inst.DeductionInfo = DeductionInfo;
Inst.InstantiationRange = InstantiationRange;
+ AlreadyInstantiating =
+ !SemaRef.InstantiatingSpecializations
+ .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind))
+ .second;
SemaRef.InNonInstantiationSFINAEContext = false;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
if (!Inst.isInstantiationRecord())
@@ -250,13 +254,14 @@
PointOfInstantiation, InstantiationRange, Entity) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
- Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template,
- ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange)
+ Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param,
+ TemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs,
+ SourceRange InstantiationRange)
: InstantiatingTemplate(
SemaRef,
ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation,
- PointOfInstantiation, InstantiationRange, Template, nullptr,
- TemplateArgs) {}
+ PointOfInstantiation, InstantiationRange, getAsNamedDecl(Param),
+ Template, TemplateArgs) {}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -266,7 +271,11 @@
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
: InstantiatingTemplate(SemaRef, Kind, PointOfInstantiation,
InstantiationRange, FunctionTemplate, nullptr,
- TemplateArgs, &DeductionInfo) {}
+ TemplateArgs, &DeductionInfo) {
+ assert(
+ Kind == ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution ||
+ Kind == ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
+}
Sema::InstantiatingTemplate::InstantiatingTemplate(
Sema &SemaRef, SourceLocation PointOfInstantiation,
@@ -330,7 +339,8 @@
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
- if (!SemaRef.ActiveTemplateInstantiations.back().isInstantiationRecord()) {
+ auto &Active = SemaRef.ActiveTemplateInstantiations.back();
+ if (!Active.isInstantiationRecord()) {
assert(SemaRef.NonInstantiationEntries > 0);
--SemaRef.NonInstantiationEntries;
}
@@ -348,6 +358,10 @@
SemaRef.ActiveTemplateInstantiationLookupModules.pop_back();
}
+ if (!AlreadyInstantiating)
+ SemaRef.InstantiatingSpecializations.erase(
+ std::make_pair(Active.Entity, Active.Kind));
+
SemaRef.ActiveTemplateInstantiations.pop_back();
Invalid = true;
}
@@ -446,7 +460,7 @@
}
case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: {
- TemplateDecl *Template = cast<TemplateDecl>(Active->Entity);
+ TemplateDecl *Template = cast<TemplateDecl>(Active->Template);
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
Template->printName(OS);
@@ -1897,6 +1911,7 @@
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst.isInvalid())
return true;
+ assert(!Inst.isAlreadyInstantiating() && "should have been caught by caller");
PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(),
"instantiating class definition");
@@ -2122,6 +2137,8 @@
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst.isInvalid())
return true;
+ if (Inst.isAlreadyInstantiating())
+ return false;
PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(),
"instantiating enum definition");
@@ -2196,6 +2213,12 @@
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst.isInvalid())
return true;
+ if (Inst.isAlreadyInstantiating()) {
+ // Error out if we hit an instantiation cycle for this initializer.
+ Diag(PointOfInstantiation, diag::err_in_class_initializer_cycle)
+ << Instantiation;
+ return true;
+ }
PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(),
"instantiating default member init");
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 3f4a0f6..2568b6c 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3396,6 +3396,13 @@
UpdateExceptionSpec(Decl, EST_None);
return;
}
+ if (Inst.isAlreadyInstantiating()) {
+ // This exception specification indirectly depends on itself. Reject.
+ // FIXME: Corresponding rule in the standard?
+ Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl;
+ UpdateExceptionSpec(Decl, EST_None);
+ return;
+ }
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
@@ -3554,23 +3561,38 @@
const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
assert(PatternDecl && "instantiating a non-template");
- Stmt *Pattern = PatternDecl->getBody(PatternDecl);
- assert(PatternDecl && "template definition is not a template");
- if (!Pattern) {
- // Try to find a defaulted definition
- PatternDecl->isDefined(PatternDecl);
- }
- assert(PatternDecl && "template definition is not a template");
+ const FunctionDecl *PatternDef = PatternDecl->getDefinition();
+ Stmt *Pattern = PatternDef->getBody(PatternDef);
+ if (PatternDef)
+ PatternDecl = PatternDef;
// FIXME: We need to track the instantiation stack in order to know which
// definitions should be visible within this instantiation.
if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Function,
Function->getInstantiatedFromMemberFunction(),
- PatternDecl, PatternDecl, TSK,
- /*Complain*/DefinitionRequired))
- return;
+ PatternDecl, PatternDef, TSK,
+ /*Complain*/DefinitionRequired)) {
+ if (DefinitionRequired)
+ Function->setInvalidDecl();
+ else if (TSK == TSK_ExplicitInstantiationDefinition) {
+ // Try again at the end of the translation unit (at which point a
+ // definition will be required).
+ assert(!Recursive);
+ PendingInstantiations.push_back(
+ std::make_pair(Function, PointOfInstantiation));
+ } else if (TSK == TSK_ImplicitInstantiation) {
+ if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {
+ Diag(PointOfInstantiation, diag::warn_func_template_missing)
+ << Function;
+ Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
+ if (getLangOpts().CPlusPlus11)
+ Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
+ << Function;
+ }
+ }
-
+ return;
+ }
// Postpone late parsed template instantiations.
if (PatternDecl->isLateTemplateParsed() &&
@@ -3604,40 +3626,9 @@
Pattern = PatternDecl->getBody(PatternDecl);
}
- // FIXME: Check if we could sink these diagnostics in
- // DiagnoseUninstantiableTemplate.
- if (!Pattern && !PatternDecl->isDefaulted()) {
- if (DefinitionRequired) {
- if (Function->getPrimaryTemplate())
- Diag(PointOfInstantiation,
- diag::err_explicit_instantiation_undefined_func_template)
- << Function->getPrimaryTemplate();
- else
- Diag(PointOfInstantiation,
- diag::err_explicit_instantiation_undefined_member)
- << 1 << Function->getDeclName() << Function->getDeclContext();
-
- if (PatternDecl)
- Diag(PatternDecl->getLocation(),
- diag::note_explicit_instantiation_here);
- Function->setInvalidDecl();
- } else if (TSK == TSK_ExplicitInstantiationDefinition) {
- assert(!Recursive);
- PendingInstantiations.push_back(
- std::make_pair(Function, PointOfInstantiation));
- } else if (TSK == TSK_ImplicitInstantiation) {
- if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {
- Diag(PointOfInstantiation, diag::warn_func_template_missing)
- << Function;
- Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
- if (getLangOpts().CPlusPlus11)
- Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
- << Function;
- }
- }
-
- return;
- }
+ // Note, we should never try to instantiate a deleted function template.
+ assert((Pattern || PatternDecl->isDefaulted()) &&
+ "unexpected kind of function template definition");
// C++1y [temp.explicit]p10:
// Except for inline functions, declarations with types deduced from their
@@ -3661,7 +3652,7 @@
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
- if (Inst.isInvalid())
+ if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
return;
PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(),
"instantiating function definition");
@@ -3928,10 +3919,6 @@
else if (OldVar->isInline())
Var->setImplicitlyInline();
- if (Var->getAnyInitializer())
- // We already have an initializer in the class.
- return;
-
if (OldVar->getInit()) {
if (Var->isStaticDataMember() && !OldVar->isOutOfLine())
PushExpressionEvaluationContext(Sema::ConstantEvaluated, OldVar);
@@ -3967,9 +3954,23 @@
}
PopExpressionEvaluationContext();
- } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) &&
- !Var->isCXXForRangeDecl())
+ } else {
+ if (Var->isStaticDataMember()) {
+ if (!Var->isOutOfLine())
+ return;
+
+ // If the declaration inside the class had an initializer, don't add
+ // another one to the out-of-line definition.
+ if (OldVar->getFirstDecl()->hasInit())
+ return;
+ }
+
+ // We'll add an initializer to a for-range declaration later.
+ if (Var->isCXXForRangeDecl())
+ return;
+
ActOnUninitializedDecl(Var, false);
+ }
}
/// \brief Instantiate the definition of the given variable from its
@@ -4059,11 +4060,15 @@
// FIXME: Factor out the duplicated instantiation context setup/tear down
// code here.
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
- if (Inst.isInvalid())
+ if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
return;
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.
@@ -4112,33 +4117,17 @@
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)
@@ -4147,12 +4136,20 @@
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)
@@ -4188,7 +4185,7 @@
}
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
- if (Inst.isInvalid())
+ if (Inst.isInvalid() || Inst.isAlreadyInstantiating())
return;
PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(),
"instantiating variable definition");
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ef71b0a..f173510 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -6890,6 +6890,14 @@
return false;
}
D = ED->getDefinition();
+ } else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ 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");
@@ -6897,7 +6905,7 @@
if (isVisible(D))
return true;
- // The external source may have additional definitions of this type that are
+ // The external source may have additional definitions of this entity that are
// visible, so complete the redeclaration chain now and ask again.
if (auto *Source = Context.getExternalSource()) {
Source->CompleteRedeclChain(D);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index 325b379..f526738 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -3416,6 +3416,31 @@
}
}
+/// We've merged the definition \p MergedDef into the existing definition
+/// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made
+/// visible.
+void ASTReader::mergeDefinitionVisibility(NamedDecl *Def,
+ NamedDecl *MergedDef) {
+ // FIXME: This doesn't correctly handle the case where MergedDef is visible
+ // in modules other than its owning module. We should instead give the
+ // ASTContext a list of merged definitions for Def.
+ if (Def->isHidden()) {
+ // If MergedDef is visible or becomes visible, make the definition visible.
+ if (!MergedDef->isHidden())
+ Def->Hidden = false;
+ else if (getContext().getLangOpts().ModulesLocalVisibility) {
+ getContext().mergeDefinitionIntoModule(
+ Def, MergedDef->getImportedOwningModule(),
+ /*NotifyListeners*/ false);
+ PendingMergedDefinitionsToDeduplicate.insert(Def);
+ } else {
+ auto SubmoduleID = MergedDef->getOwningModuleID();
+ assert(SubmoduleID && "hidden definition in no module");
+ HiddenNamesMap[getSubmodule(SubmoduleID)].push_back(Def);
+ }
+ }
+}
+
bool ASTReader::loadGlobalIndex() {
if (GlobalIndex)
return false;
@@ -8491,8 +8516,11 @@
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) {
// FIXME: Check for =delete/=default?
// FIXME: Complain about ODR violations here?
- if (!getContext().getLangOpts().Modules || !FD->hasBody())
+ const FunctionDecl *Defn = nullptr;
+ if (!getContext().getLangOpts().Modules || !FD->hasBody(Defn))
FD->setLazyBody(PB->second);
+ else
+ mergeDefinitionVisibility(const_cast<FunctionDecl*>(Defn), FD);
continue;
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 7f9ad96..3039149 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -382,27 +382,6 @@
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D);
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
-
- /// We've merged the definition \p MergedDef into the existing definition
- /// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made
- /// visible.
- void mergeDefinitionVisibility(NamedDecl *Def, NamedDecl *MergedDef) {
- if (Def->isHidden()) {
- // If MergedDef is visible or becomes visible, make the definition visible.
- if (!MergedDef->isHidden())
- Def->Hidden = false;
- else if (Reader.getContext().getLangOpts().ModulesLocalVisibility) {
- Reader.getContext().mergeDefinitionIntoModule(
- Def, MergedDef->getImportedOwningModule(),
- /*NotifyListeners*/ false);
- Reader.PendingMergedDefinitionsToDeduplicate.insert(Def);
- } else {
- auto SubmoduleID = MergedDef->getOwningModuleID();
- assert(SubmoduleID && "hidden definition in no module");
- Reader.HiddenNamesMap[Reader.getSubmodule(SubmoduleID)].push_back(Def);
- }
- }
- }
};
} // end namespace clang
@@ -709,7 +688,7 @@
if (OldDef) {
Reader.MergedDeclContexts.insert(std::make_pair(ED, OldDef));
ED->IsCompleteDefinition = false;
- mergeDefinitionVisibility(OldDef, ED);
+ Reader.mergeDefinitionVisibility(OldDef, ED);
} else {
OldDef = ED;
}
@@ -1236,6 +1215,7 @@
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++];
@@ -1256,7 +1236,7 @@
if (uint64_t Val = Record[Idx++]) {
VD->setInit(Reader.ReadExpr(F));
- if (Val > 1) {
+ if (Val > 1) { // IsInitKnownICE = 1, IsInitNotICE = 2, IsInitICE = 3
EvaluatedStmt *Eval = VD->ensureEvaluatedStmt();
Eval->CheckedICE = true;
Eval->IsICE = Val == 3;
@@ -1597,7 +1577,7 @@
DD.Definition));
Reader.PendingDefinitions.erase(MergeDD.Definition);
MergeDD.Definition->IsCompleteDefinition = false;
- mergeDefinitionVisibility(DD.Definition, MergeDD.Definition);
+ Reader.mergeDefinitionVisibility(DD.Definition, MergeDD.Definition);
assert(Reader.Lookups.find(MergeDD.Definition) == Reader.Lookups.end() &&
"already loaded pending lookups for merged definition");
}
@@ -3083,6 +3063,29 @@
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);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index 158123b..7b12bf0 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -893,6 +893,7 @@
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());
@@ -941,8 +942,6 @@
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
- D->getInitStyle() == VarDecl::CInit &&
- D->getInit() == nullptr &&
D->getKind() == Decl::Var &&
!D->isInline() &&
!D->isConstexpr() &&
@@ -999,6 +998,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");
@@ -1873,9 +1874,9 @@
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)); // Linkage
Abv->Add(BitCodeAbbrevOp(0)); // HasInit
Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo
@@ -1949,9 +1950,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::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
@@ -1962,8 +1964,8 @@
Abv->Add(BitCodeAbbrevOp(0)); // isInitCapture
Abv->Add(BitCodeAbbrevOp(0)); // isPrevDeclInSameScope
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // Linkage
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit
- Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // IsInitICE (local)
+ Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // VarKind (local enum)
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp
index 61b9675..7db5d53 100644
--- a/test/Index/Core/index-source.cpp
+++ b/test/Index/Core/index-source.cpp
@@ -1,4 +1,4 @@
-// RUN: c-index-test core -print-source-symbols -- %s -target x86_64-apple-macosx10.7 | FileCheck %s
+// RUN: c-index-test core -print-source-symbols -- %s -std=c++14 -target x86_64-apple-macosx10.7 | FileCheck %s
template <typename TemplArg>
class TemplCls {
@@ -29,3 +29,14 @@
// CHECK: [[@LINE+2]]:7 | function/C | operator new | c:@F@operator new#l# | __Znwm |
// CHECK: [[@LINE+1]]:20 | type-alias/C | size_t | {{.*}} | Ref |
void* operator new(size_t sz);
+
+// CHECK: [[@LINE+1]]:37 | variable(Gen)/C++ | tmplVar | c:index-source.cpp@VT>1#T@tmplVar | __ZL7tmplVar | Def | rel: 0
+template<typename T> static const T tmplVar = T(0);
+// CHECK: [[@LINE+1]]:29 | variable(Gen,TS)/C++ | tmplVar | c:index-source.cpp@tmplVar>#I | __ZL7tmplVarIiE | Def | rel: 0
+template<> static const int tmplVar<int> = 0;
+// CHECK: [[@LINE+2]]:5 | variable/C | gvi | c:@gvi | _gvi | Def | rel: 0
+// CHECK: [[@LINE+1]]:11 | variable(Gen,TS)/C++ | tmplVar | c:index-source.cpp@tmplVar>#I | __ZL7tmplVarIiE | Ref,Read | rel: 0
+int gvi = tmplVar<int>;
+// CHECK: [[@LINE+2]]:5 | variable/C | gvf | c:@gvf | _gvf | Def | rel: 0
+// CHECK: [[@LINE+1]]:11 | variable(Gen)/C++ | tmplVar | c:index-source.cpp@VT>1#T@tmplVar | __ZL7tmplVar | Ref,Read | rel: 0
+int gvf = tmplVar<float>;
diff --git a/test/Modules/Inputs/PR28752/Subdir1/b.h b/test/Modules/Inputs/PR28752/Subdir1/b.h
new file mode 100644
index 0000000..4d8de21
--- /dev/null
+++ b/test/Modules/Inputs/PR28752/Subdir1/b.h
@@ -0,0 +1,4 @@
+#include <vector>
+
+template<typename T> struct A { static bool b; };
+template<typename T> bool A<T>::b;
diff --git a/test/Modules/Inputs/PR28752/Subdir1/c.h b/test/Modules/Inputs/PR28752/Subdir1/c.h
new file mode 100644
index 0000000..38822fb
--- /dev/null
+++ b/test/Modules/Inputs/PR28752/Subdir1/c.h
@@ -0,0 +1,2 @@
+template<typename T> struct A { static bool b; };
+template<typename T> bool A<T>::b;
diff --git a/test/Modules/Inputs/PR28752/Subdir1/module.modulemap b/test/Modules/Inputs/PR28752/Subdir1/module.modulemap
new file mode 100644
index 0000000..8d3bfe9
--- /dev/null
+++ b/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 *
+}
diff --git a/test/Modules/Inputs/PR28752/a.h b/test/Modules/Inputs/PR28752/a.h
new file mode 100644
index 0000000..3b3a25f
--- /dev/null
+++ b/test/Modules/Inputs/PR28752/a.h
@@ -0,0 +1 @@
+#include <vector>
diff --git a/test/Modules/Inputs/PR28752/module.modulemap b/test/Modules/Inputs/PR28752/module.modulemap
new file mode 100644
index 0000000..caf888f
--- /dev/null
+++ b/test/Modules/Inputs/PR28752/module.modulemap
@@ -0,0 +1 @@
+module a { header "a.h" export * }
diff --git a/test/Modules/Inputs/PR28752/vector b/test/Modules/Inputs/PR28752/vector
new file mode 100644
index 0000000..fc5dafa
--- /dev/null
+++ b/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
diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/a.h b/test/Modules/Inputs/merge-template-pattern-visibility/a.h
index 7f9b649..e659202 100644
--- a/test/Modules/Inputs/merge-template-pattern-visibility/a.h
+++ b/test/Modules/Inputs/merge-template-pattern-visibility/a.h
@@ -3,3 +3,4 @@
template<typename, typename> struct A {};
template<typename T> struct B : A<T> {};
+template<typename T> inline auto C(T) {}
diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/b.h b/test/Modules/Inputs/merge-template-pattern-visibility/b.h
index 5ed18e7..41b52d5 100644
--- a/test/Modules/Inputs/merge-template-pattern-visibility/b.h
+++ b/test/Modules/Inputs/merge-template-pattern-visibility/b.h
@@ -3,7 +3,18 @@
template<typename, typename> struct A {};
template<typename T> struct B : A<T> {};
+template<typename T> inline auto C(T) {}
inline void f() {
B<int> bi;
+ C(0);
+}
+
+namespace CrossModuleMerge {
+ template<typename, typename = int> struct A;
+ template<typename T> struct B;
+
+ template<typename, typename> struct A {};
+ template<typename T> struct B : A<T> {};
+ template<typename T> inline auto C(T) {}
}
diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/c.h b/test/Modules/Inputs/merge-template-pattern-visibility/c.h
new file mode 100644
index 0000000..db80eda
--- /dev/null
+++ b/test/Modules/Inputs/merge-template-pattern-visibility/c.h
@@ -0,0 +1,9 @@
+namespace CrossModuleMerge {
+ template<typename, typename = int> struct A;
+ template<typename T> struct B;
+
+ template<typename, typename> struct A {};
+ template<typename T> struct B : A<T> {};
+ template<typename T> inline auto C(T) {}
+}
+
diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/d.h b/test/Modules/Inputs/merge-template-pattern-visibility/d.h
new file mode 100644
index 0000000..464f0f5
--- /dev/null
+++ b/test/Modules/Inputs/merge-template-pattern-visibility/d.h
@@ -0,0 +1 @@
+// d.h: empty
diff --git a/test/Modules/Inputs/merge-template-pattern-visibility/module.modulemap b/test/Modules/Inputs/merge-template-pattern-visibility/module.modulemap
index ba97abb..e00d1b9 100644
--- a/test/Modules/Inputs/merge-template-pattern-visibility/module.modulemap
+++ b/test/Modules/Inputs/merge-template-pattern-visibility/module.modulemap
@@ -2,3 +2,7 @@
module A { header "a.h" }
module B { header "b.h" }
}
+module Y {
+ module C { header "c.h" }
+ module D { header "d.h" }
+}
diff --git a/test/Modules/Inputs/merge-var-template-def/a.h b/test/Modules/Inputs/merge-var-template-def/a.h
new file mode 100644
index 0000000..6b414b3
--- /dev/null
+++ b/test/Modules/Inputs/merge-var-template-def/a.h
@@ -0,0 +1,8 @@
+#ifndef A_H
+#define A_H
+template<typename T, T v>
+struct S { static constexpr T value = v; };
+template<typename T, T v>
+constexpr T S<T, v>::value;
+
+#endif
diff --git a/test/Modules/Inputs/merge-var-template-def/b1.h b/test/Modules/Inputs/merge-var-template-def/b1.h
new file mode 100644
index 0000000..35cab9d
--- /dev/null
+++ b/test/Modules/Inputs/merge-var-template-def/b1.h
@@ -0,0 +1,9 @@
+#ifndef B1_H
+#define B1_H
+template<typename T, T v>
+struct S { static constexpr T value = v; };
+template<typename T, T v>
+constexpr T S<T, v>::value;
+
+#include "a.h"
+#endif
diff --git a/test/Modules/Inputs/merge-var-template-def/b2.h b/test/Modules/Inputs/merge-var-template-def/b2.h
new file mode 100644
index 0000000..6ab87c2
--- /dev/null
+++ b/test/Modules/Inputs/merge-var-template-def/b2.h
@@ -0,0 +1,9 @@
+#ifndef B2_H
+#define B2_H
+
+template<typename T, T v>
+struct S { static constexpr T value = v; };
+template<typename T, T v>
+constexpr T S<T, v>::value;
+
+#endif
diff --git a/test/Modules/Inputs/merge-var-template-def/module.modulemap b/test/Modules/Inputs/merge-var-template-def/module.modulemap
new file mode 100644
index 0000000..b2c96bd
--- /dev/null
+++ b/test/Modules/Inputs/merge-var-template-def/module.modulemap
@@ -0,0 +1,5 @@
+module a { header "a.h" export * }
+module b {
+ module b1 { header "b1.h" export * }
+ module b2 { header "b2.h" export * }
+}
diff --git a/test/Modules/merge-template-pattern-visibility.cpp b/test/Modules/merge-template-pattern-visibility.cpp
index db759b5..ec5aa26 100644
--- a/test/Modules/merge-template-pattern-visibility.cpp
+++ b/test/Modules/merge-template-pattern-visibility.cpp
@@ -1,4 +1,18 @@
// RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fno-modules-error-recovery \
+// RUN: %clang_cc1 -fmodules -fno-modules-error-recovery -std=c++14 \
// RUN: -fmodule-name=X -emit-module %S/Inputs/merge-template-pattern-visibility/module.modulemap -x c++ \
-// RUN: -fmodules-local-submodule-visibility
+// RUN: -fmodules-local-submodule-visibility -o %t/X.pcm
+// RUN: %clang_cc1 -fmodules -fno-modules-error-recovery -std=c++14 \
+// RUN: -fmodule-name=Y -emit-module %S/Inputs/merge-template-pattern-visibility/module.modulemap -x c++ \
+// RUN: -fmodules-local-submodule-visibility -o %t/Y.pcm
+// RUN: %clang_cc1 -fmodules -fno-modules-error-recovery -std=c++14 -fmodule-file=%t/X.pcm -fmodule-file=%t/Y.pcm \
+// RUN: -fmodules-local-submodule-visibility -verify %s -I%S/Inputs/merge-template-pattern-visibility
+
+#include "b.h"
+#include "d.h"
+
+// expected-no-diagnostics
+void g() {
+ CrossModuleMerge::B<int> bi;
+ CrossModuleMerge::C(0);
+}
diff --git a/test/Modules/merge-var-template-def.cpp b/test/Modules/merge-var-template-def.cpp
new file mode 100644
index 0000000..97a72a1
--- /dev/null
+++ b/test/Modules/merge-var-template-def.cpp
@@ -0,0 +1,7 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I%S/Inputs/merge-var-template-def -std=c++11 -verify %s
+// RUN: %clang_cc1 -I%S/Inputs/merge-var-template-def -std=c++11 -verify -fmodules -Werror=undefined-internal -fmodules-local-submodule-visibility -fmodules-cache-path=%t -fimplicit-module-maps %s
+// expected-no-diagnostics
+
+#include "b2.h"
+const bool *y = &S<bool, false>::value;
diff --git a/test/Modules/pr28752.cpp b/test/Modules/pr28752.cpp
new file mode 100644
index 0000000..1c78961
--- /dev/null
+++ b/test/Modules/pr28752.cpp
@@ -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
+
diff --git a/test/SemaTemplate/instantiate-self.cpp b/test/SemaTemplate/instantiate-self.cpp
index cfe9025..916a01e 100644
--- a/test/SemaTemplate/instantiate-self.cpp
+++ b/test/SemaTemplate/instantiate-self.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++1z -verify -pedantic-errors %s
// Check that we deal with cases where the instantiation of a class template
// recursively requires the instantiation of the same template.
@@ -47,9 +47,8 @@
A<int> a; // expected-note {{in instantiation of}}
}
-// FIXME: PR12298: Recursive constexpr function template instantiation leads to
+// PR12298: Recursive constexpr function template instantiation leads to
// stack overflow.
-#if 0
namespace test5 {
template<typename T> struct A {
constexpr T f(T k) { return g(k); }
@@ -57,22 +56,20 @@
return k ? f(k-1)+1 : 0;
}
};
- // This should be accepted.
- constexpr int x = A<int>().f(5);
+ constexpr int x = A<int>().f(5); // ok
}
namespace test6 {
template<typename T> constexpr T f(T);
template<typename T> constexpr T g(T t) {
- typedef int arr[f(T())];
+ typedef int arr[f(T())]; // expected-error {{variable length array}}
return t;
}
template<typename T> constexpr T f(T t) {
- typedef int arr[g(T())];
+ typedef int arr[g(T())]; // expected-error {{zero size array}} expected-note {{instantiation of}}
return t;
}
- // This should be ill-formed.
- int n = f(0);
+ int n = f(0); // expected-note 2{{instantiation of}}
}
namespace test7 {
@@ -80,10 +77,94 @@
return t;
}
template<typename T> constexpr T f(T t) {
- typedef int arr[g(T())];
+ typedef int arr[g(T() + 1)];
return t;
}
- // This should be accepted.
int n = f(0);
}
+
+namespace test8 {
+ template<typename T> struct A {
+ int n = A{}.n; // expected-error {{default member initializer for 'n' uses itself}} expected-note {{instantiation of default member init}}
+ };
+ A<int> ai = {}; // expected-note {{instantiation of default member init}}
+}
+
+namespace test9 {
+ template<typename T> struct A { enum class B; };
+ // FIXME: It'd be nice to give the "it has not yet been instantiated" diagnostic here.
+ template<typename T> enum class A<T>::B { k = A<T>::B::k2, k2 = k }; // expected-error {{no member named 'k2'}}
+ auto k = A<int>::B::k; // expected-note {{in instantiation of}}
+}
+
+namespace test10 {
+ template<typename T> struct A {
+ void f() noexcept(noexcept(f())); // expected-error {{exception specification of 'f' uses itself}} expected-note {{instantiation of}}
+ };
+ bool b = noexcept(A<int>().f()); // expected-note {{instantiation of}}
+}
+
+namespace test11 {
+ template<typename T> const int var = var<T>;
+ int k = var<int>;
+
+ template<typename T> struct X {
+ static const int k = X<T>::k;
+ };
+ template<typename T> const int X<T>::k;
+ int q = X<int>::k;
+
+ template<typename T> struct Y {
+ static const int k;
+ };
+ template<typename T> const int Y<T>::k = Y<T>::k;
+ int r = Y<int>::k;
+}
+
+namespace test12 {
+ template<typename T> int f(T t, int = f(T())) {} // expected-error {{recursive evaluation of default argument}} expected-note {{instantiation of}}
+ struct X {};
+ int q = f(X()); // expected-note {{instantiation of}}
+}
+
+namespace test13 {
+ struct A {
+ // Cycle via type of non-type template parameter.
+ template<typename T, typename T::template W<T>::type U = 0> struct W { using type = int; };
+ // Cycle via default template argument.
+ template<typename T, typename U = typename T::template X<T>> struct X {};
+ template<typename T, int U = T::template Y<T>::value> struct Y { static const int value = 0; };
+ template<typename T, template<typename> typename U = T::template Z<T>::template nested> struct Z { template<typename> struct nested; };
+ };
+ template<typename T> struct Wrap {
+ template<typename U> struct W : A::W<T> {};
+ template<typename U> struct X : A::X<T> {};
+ template<typename U> struct Y : A::Y<T> {};
+ template<typename U> struct Z : A::Z<T> {};
+ };
+ struct B {
+ template<typename U> struct W { using type = int; };
+ template<typename U> struct X {};
+ template<typename U> struct Y { static const int value = 0; };
+ template<typename U> struct Z { template<typename> struct nested; };
+ };
+
+ A::W<B> awb;
+ A::X<B> axb;
+ A::Y<B> ayb;
+ A::Z<B> azb;
+
+ A::W<Wrap<Wrap<B>>> awwwb;
+ A::X<Wrap<Wrap<B>>> axwwb;
+ A::Y<Wrap<Wrap<B>>> aywwb;
+ A::Z<Wrap<Wrap<B>>> azwwb;
+
+ // FIXME: These tests cause us to use too much stack and crash on a self-hosted debug build.
+ // FIXME: Check for recursion here and give a better diagnostic.
+#if 0
+ A::W<A> awa;
+ A::X<A> axa;
+ A::Y<A> aya;
+ A::Z<A> aza;
#endif
+}
diff --git a/test/SemaTemplate/instantiation-depth-exception-spec.cpp b/test/SemaTemplate/instantiation-depth-exception-spec.cpp
index 6caa4a6..3f64811 100644
--- a/test/SemaTemplate/instantiation-depth-exception-spec.cpp
+++ b/test/SemaTemplate/instantiation-depth-exception-spec.cpp
@@ -1,11 +1,14 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -ftemplate-depth 16 -fcxx-exceptions -fexceptions %s
-template<typename T> T go(T a) noexcept(noexcept(go(a))); // \
-// expected-error 16{{call to function 'go' that is neither visible}} \
-// expected-note 16{{'go' should be declared prior to the call site}} \
-// expected-error {{recursive template instantiation exceeded maximum depth of 16}}
+template<int N> struct X {
+ static int go(int a) noexcept(noexcept(X<N+1>::go(a))); // \
+// expected-error {{recursive template instantiation exceeded maximum depth of 16}} \
+// expected-note 9{{in instantiation of exception specification}} \
+// expected-note {{skipping 7 context}} \
+// expected-note {{use -ftemplate-depth}}
+};
void f() {
- int k = go(0); // \
- // expected-note {{in instantiation of exception specification for 'go<int>' requested here}}
+ int k = X<0>::go(0); // \
+ // expected-note {{in instantiation of exception specification for 'go' requested here}}
}
diff --git a/test/SemaTemplate/instantiation-depth.cpp b/test/SemaTemplate/instantiation-depth.cpp
index c0b8bb2..17f84c1 100644
--- a/test/SemaTemplate/instantiation-depth.cpp
+++ b/test/SemaTemplate/instantiation-depth.cpp
@@ -19,13 +19,12 @@
// RUN: %clang_cc1 -fsyntax-only -verify -ftemplate-depth 5 -ftemplate-backtrace-limit 4 -std=c++11 -DNOEXCEPT %s
template<typename T> struct S {
- S() noexcept(noexcept(T()));
-};
-struct T : S<T> {}; \
+ S() noexcept(noexcept(S<S>())); \
// expected-error{{recursive template instantiation exceeded maximum depth of 5}} \
-// expected-note 4 {{in instantiation of exception spec}} \
+// expected-note 3 {{in instantiation of exception spec}} \
// expected-note {{skipping 2 contexts in backtrace}} \
// expected-note {{use -ftemplate-depth=N to increase recursive template instantiation depth}}
-T t; // expected-note {{implicit default constructor for 'T' first required here}}
+};
+S<void> t; // expected-note {{in instantiation of exception spec}}
#endif