}
};
-/// Storage for a default argument.
+/// Storage for a default argument. This is conceptually either empty, or an
+/// argument value, or a pointer to a previous declaration that had a default
+/// argument.
+///
+/// However, this is complicated by modules: while we require all the default
+/// arguments for a template to be equivalent, there may be more than one, and
+/// we need to track all the originating parameters to determine if the default
+/// argument is visible.
template<typename ParmDecl, typename ArgType>
class DefaultArgStorage {
- llvm::PointerUnion<ArgType, ParmDecl*> ValueOrInherited;
+ /// Storage for both the value *and* another parameter from which we inherit
+ /// the default argument. This is used when multiple default arguments for a
+ /// parameter are merged together from different modules.
+ struct Chain {
+ ParmDecl *PrevDeclWithDefaultArg;
+ ArgType Value;
+ };
+ static_assert(sizeof(Chain) == sizeof(void *) * 2,
+ "non-pointer argument type?");
+
+ llvm::PointerUnion3<ArgType, ParmDecl*, Chain*> ValueOrInherited;
static ParmDecl *getParmOwningDefaultArg(ParmDecl *Parm) {
const DefaultArgStorage &Storage = Parm->getDefaultArgStorage();
if (auto *Prev = Storage.ValueOrInherited.template dyn_cast<ParmDecl*>())
Parm = Prev;
- assert(
- Parm->getDefaultArgStorage().ValueOrInherited.template is<ArgType>() &&
- "should only be one level of indirection");
+ assert(!Parm->getDefaultArgStorage()
+ .ValueOrInherited.template is<ParmDecl *>() &&
+ "should only be one level of indirection");
return Parm;
}
/// Determine whether the default argument for this parameter was inherited
/// from a previous declaration of the same entity.
bool isInherited() const { return ValueOrInherited.template is<ParmDecl*>(); }
- /// Get the default argument's value.
+ /// Get the default argument's value. This does not consider whether the
+ /// default argument is visible.
ArgType get() const {
const DefaultArgStorage *Storage = this;
if (auto *Prev = ValueOrInherited.template dyn_cast<ParmDecl*>())
Storage = &Prev->getDefaultArgStorage();
+ if (auto *C = ValueOrInherited.template dyn_cast<Chain*>())
+ return C->Value;
return Storage->ValueOrInherited.template get<ArgType>();
}
/// Get the parameter from which we inherit the default argument, if any.
/// This is the parameter on which the default argument was actually written.
const ParmDecl *getInheritedFrom() const {
- return ValueOrInherited.template dyn_cast<ParmDecl*>();
+ if (auto *D = ValueOrInherited.template dyn_cast<ParmDecl*>())
+ return D;
+ if (auto *C = ValueOrInherited.template dyn_cast<Chain*>())
+ return C->PrevDeclWithDefaultArg;
+ return nullptr;
}
/// Set the default argument.
void set(ArgType Arg) {
}
/// Set that the default argument was inherited from another parameter.
void setInherited(const ASTContext &C, ParmDecl *InheritedFrom) {
- assert(!isSet() && "default argument already set");
- ValueOrInherited = getParmOwningDefaultArg(InheritedFrom);
+ // Defined in DeclTemplate.cpp.
+ extern void *allocateDefaultArgStorageChain(const ASTContext &C);
+
+ assert(!isInherited() && "default argument already inherited");
+ InheritedFrom = getParmOwningDefaultArg(InheritedFrom);
+ if (!isSet())
+ ValueOrInherited = InheritedFrom;
+ else
+ ValueOrInherited = new (allocateDefaultArgStorageChain(C))
+ Chain{InheritedFrom, ValueOrInherited.template get<ArgType>()};
}
/// Remove the default argument, even if it was inherited.
void clear() {
if (!D->isInIdentifierNamespace(IDNS))
return nullptr;
- if (isVisible(getSema(), D))
+ if (isHiddenDeclarationVisible() || isVisible(getSema(), D))
return D;
- if (auto *Visible = getAcceptableDeclSlow(D))
- return Visible;
-
- // Even if hidden declarations are visible, prefer a visible declaration.
- return isHiddenDeclarationVisible() ? D : nullptr;
+ return getAcceptableDeclSlow(D);
}
private:
return hasVisibleDefinition(const_cast<NamedDecl*>(D), &Hidden);
}
+ /// Determine if the template parameter \p D has a visible default argument.
+ bool hasVisibleDefaultArgument(const NamedDecl *D);
+
bool RequireCompleteType(SourceLocation Loc, QualType T,
TypeDiagnoser &Diagnoser);
bool RequireCompleteType(SourceLocation Loc, QualType T,
}
}
+namespace clang {
+void *allocateDefaultArgStorageChain(const ASTContext &C) {
+ return new (C) char[sizeof(void*) * 2];
+}
+}
+
//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
}
void Sema::makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc) {
+ // FIXME: If ND is a template declaration, make the template parameters
+ // visible too. They're not (necessarily) within its DeclContext.
if (auto *M = PP.getModuleContainingLocation(Loc))
Context.mergeDefinitionIntoModule(ND, M);
else
return false;
}
+template<typename ParmDecl>
+static bool hasVisibleDefaultArgument(Sema &S, const ParmDecl *D) {
+ if (!D->hasDefaultArgument())
+ return false;
+
+ while (D) {
+ auto &DefaultArg = D->getDefaultArgStorage();
+ if (!DefaultArg.isInherited() && S.isVisible(D))
+ return true;
+
+ // If there was a previous default argument, maybe its parameter is visible.
+ D = DefaultArg.getInheritedFrom();
+ }
+ return false;
+}
+
+bool Sema::hasVisibleDefaultArgument(const NamedDecl *D) {
+ if (auto *P = dyn_cast<TemplateTypeParmDecl>(D))
+ return ::hasVisibleDefaultArgument(*this, P);
+ if (auto *P = dyn_cast<NonTypeTemplateParmDecl>(D))
+ return ::hasVisibleDefaultArgument(*this, P);
+ return ::hasVisibleDefaultArgument(*this, cast<TemplateTemplateParmDecl>(D));
+}
+
/// \brief Determine whether a declaration is visible to name lookup.
///
/// This routine determines whether the declaration D is visible in the current
// Merge default arguments for template type parameters.
TemplateTypeParmDecl *OldTypeParm
= OldParams? cast<TemplateTypeParmDecl>(*OldParam) : nullptr;
- // FIXME: There might be a visible declaration of this template parameter.
- if (OldTypeParm && !LookupResult::isVisible(*this, OldTypeParm))
- OldTypeParm = nullptr;
-
if (NewTypeParm->isParameterPack()) {
assert(!NewTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
- } else if (OldTypeParm && OldTypeParm->hasDefaultArgument() &&
+ } else if (OldTypeParm && hasVisibleDefaultArgument(OldTypeParm) &&
NewTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc();
// Merge default arguments for non-type template parameters
NonTypeTemplateParmDecl *OldNonTypeParm
= OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : nullptr;
- if (OldNonTypeParm && !LookupResult::isVisible(*this, OldNonTypeParm))
- OldNonTypeParm = nullptr;
if (NewNonTypeParm->isParameterPack()) {
assert(!NewNonTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
if (!NewNonTypeParm->isPackExpansion())
SawParameterPack = true;
- } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
+ } else if (OldNonTypeParm && hasVisibleDefaultArgument(OldNonTypeParm) &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc();
// Merge default arguments for template template parameters
TemplateTemplateParmDecl *OldTemplateParm
= OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : nullptr;
- if (OldTemplateParm && !LookupResult::isVisible(*this, OldTemplateParm))
- OldTemplateParm = nullptr;
if (NewTemplateParm->isParameterPack()) {
assert(!NewTemplateParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
if (!NewTemplateParm->isPackExpansion())
SawParameterPack = true;
- } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
- NewTemplateParm->hasDefaultArgument()) {
+ } else if (OldTemplateParm &&
+ hasVisibleDefaultArgument(OldTemplateParm) &&
+ NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
NewDefaultLoc = NewTemplateParm->getDefaultArgument().getLocation();
SawDefaultArgument = true;
auto *To = cast<ParmDecl>(ToD);
if (!From->hasDefaultArgument())
return false;
- if (!To->hasDefaultArgument())
- To->setInheritedDefaultArgument(Context, From);
+ To->setInheritedDefaultArgument(Context, From);
return true;
}
template<typename T> struct B {};
template<typename T> struct C;
template<typename T> struct D;
+template<typename T> struct E;
--- /dev/null
+template<typename T = int> struct F;
-module X { module A { header "a.h" } module B { header "b.h" } }
+module X {
+ module A { header "a.h" }
+ module B { header "b.h" }
+ module C { header "c.h" }
+}
template<typename T> struct B;
template<typename T> struct C;
template<typename T = int> struct D;
+template<typename T = int> struct E {};
#include "b.h"
template<typename T = int> struct B;
template<typename T = int> struct C;
template<typename T> struct D {};
+template<typename T> struct F {};
+
+#include "c.h"
A<> a;
B<> b;
extern C<> c;
D<> d;
+E<> e;
+F<> f;