forked from OSchip/llvm-project
Itanium ABI: Properly qualify the destructor-name
We didn't have enough qualificaiton before the scope specifier and we had too much qualification in the destructor name itself. llvm-svn: 229809
This commit is contained in:
parent
0a52cd7937
commit
b8014dd7c0
|
@ -327,10 +327,8 @@ private:
|
|||
void addSubstitution(uintptr_t Ptr);
|
||||
|
||||
void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
|
||||
NamedDecl *firstQualifierLookup,
|
||||
bool recursive = false);
|
||||
void mangleUnresolvedName(NestedNameSpecifier *qualifier,
|
||||
NamedDecl *firstQualifierLookup,
|
||||
DeclarationName name,
|
||||
unsigned KnownArity = UnknownArity);
|
||||
|
||||
|
@ -360,7 +358,8 @@ private:
|
|||
void manglePrefix(QualType type);
|
||||
void mangleTemplatePrefix(const TemplateDecl *ND, bool NoFunction=false);
|
||||
void mangleTemplatePrefix(TemplateName Template);
|
||||
void mangleDestructorName(QualType DestroyedType);
|
||||
bool mangleUnresolvedTypeOrSimpleId(QualType DestroyedType,
|
||||
StringRef Prefix = "");
|
||||
void mangleOperatorName(DeclarationName Name, unsigned Arity);
|
||||
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
|
||||
void mangleQualifiers(Qualifiers Quals);
|
||||
|
@ -799,7 +798,6 @@ void CXXNameMangler::manglePrefix(QualType type) {
|
|||
/// \param recursive - true if this is being called recursively,
|
||||
/// i.e. if there is more prefix "to the right".
|
||||
void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
|
||||
NamedDecl *firstQualifierLookup,
|
||||
bool recursive) {
|
||||
|
||||
// x, ::x
|
||||
|
@ -832,7 +830,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
|
|||
|
||||
case NestedNameSpecifier::Namespace:
|
||||
if (qualifier->getPrefix())
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(),
|
||||
/*recursive*/ true);
|
||||
else
|
||||
Out << "sr";
|
||||
|
@ -840,7 +838,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
|
|||
break;
|
||||
case NestedNameSpecifier::NamespaceAlias:
|
||||
if (qualifier->getPrefix())
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(),
|
||||
/*recursive*/ true);
|
||||
else
|
||||
Out << "sr";
|
||||
|
@ -857,193 +855,26 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
|
|||
// - a template template parameter with arguments
|
||||
// In all of these cases, we should have no prefix.
|
||||
if (qualifier->getPrefix()) {
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(),
|
||||
/*recursive*/ true);
|
||||
} else {
|
||||
// Otherwise, all the cases want this.
|
||||
Out << "sr";
|
||||
}
|
||||
|
||||
// Only certain other types are valid as prefixes; enumerate them.
|
||||
switch (type->getTypeClass()) {
|
||||
case Type::Builtin:
|
||||
case Type::Complex:
|
||||
case Type::Adjusted:
|
||||
case Type::Decayed:
|
||||
case Type::Pointer:
|
||||
case Type::BlockPointer:
|
||||
case Type::LValueReference:
|
||||
case Type::RValueReference:
|
||||
case Type::MemberPointer:
|
||||
case Type::ConstantArray:
|
||||
case Type::IncompleteArray:
|
||||
case Type::VariableArray:
|
||||
case Type::DependentSizedArray:
|
||||
case Type::DependentSizedExtVector:
|
||||
case Type::Vector:
|
||||
case Type::ExtVector:
|
||||
case Type::FunctionProto:
|
||||
case Type::FunctionNoProto:
|
||||
case Type::Enum:
|
||||
case Type::Paren:
|
||||
case Type::Elaborated:
|
||||
case Type::Attributed:
|
||||
case Type::Auto:
|
||||
case Type::PackExpansion:
|
||||
case Type::ObjCObject:
|
||||
case Type::ObjCInterface:
|
||||
case Type::ObjCObjectPointer:
|
||||
case Type::Atomic:
|
||||
llvm_unreachable("type is illegal as a nested name specifier");
|
||||
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
// FIXME: not clear how to mangle this!
|
||||
// template <class T...> class A {
|
||||
// template <class U...> void foo(decltype(T::foo(U())) x...);
|
||||
// };
|
||||
Out << "_SUBSTPACK_";
|
||||
break;
|
||||
|
||||
// <unresolved-type> ::= <template-param>
|
||||
// ::= <decltype>
|
||||
// ::= <template-template-param> <template-args>
|
||||
// (this last is not official yet)
|
||||
case Type::TypeOfExpr:
|
||||
case Type::TypeOf:
|
||||
case Type::Decltype:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::UnaryTransform:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
unresolvedType:
|
||||
assert(!qualifier->getPrefix());
|
||||
|
||||
// We only get here recursively if we're followed by identifiers.
|
||||
if (recursive) Out << 'N';
|
||||
|
||||
// This seems to do everything we want. It's not really
|
||||
// sanctioned for a substituted template parameter, though.
|
||||
mangleType(QualType(type, 0));
|
||||
|
||||
// We never want to print 'E' directly after an unresolved-type,
|
||||
// so we return directly.
|
||||
if (mangleUnresolvedTypeOrSimpleId(QualType(type, 0), recursive ? "N" : ""))
|
||||
return;
|
||||
|
||||
case Type::Typedef:
|
||||
mangleSourceName(cast<TypedefType>(type)->getDecl()->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::UnresolvedUsing:
|
||||
mangleSourceName(cast<UnresolvedUsingType>(type)->getDecl()
|
||||
->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::Record:
|
||||
mangleSourceName(cast<RecordType>(type)->getDecl()->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::TemplateSpecialization: {
|
||||
const TemplateSpecializationType *tst
|
||||
= cast<TemplateSpecializationType>(type);
|
||||
TemplateName name = tst->getTemplateName();
|
||||
switch (name.getKind()) {
|
||||
case TemplateName::Template:
|
||||
case TemplateName::QualifiedTemplate: {
|
||||
TemplateDecl *temp = name.getAsTemplateDecl();
|
||||
|
||||
// If the base is a template template parameter, this is an
|
||||
// unresolved type.
|
||||
assert(temp && "no template for template specialization type");
|
||||
if (isa<TemplateTemplateParmDecl>(temp)) goto unresolvedType;
|
||||
|
||||
mangleSourceName(temp->getIdentifier());
|
||||
break;
|
||||
}
|
||||
|
||||
case TemplateName::OverloadedTemplate:
|
||||
case TemplateName::DependentTemplate:
|
||||
llvm_unreachable("invalid base for a template specialization type");
|
||||
|
||||
case TemplateName::SubstTemplateTemplateParm: {
|
||||
SubstTemplateTemplateParmStorage *subst
|
||||
= name.getAsSubstTemplateTemplateParm();
|
||||
mangleExistingSubstitution(subst->getReplacement());
|
||||
break;
|
||||
}
|
||||
|
||||
case TemplateName::SubstTemplateTemplateParmPack: {
|
||||
// FIXME: not clear how to mangle this!
|
||||
// template <template <class U> class T...> class A {
|
||||
// template <class U...> void foo(decltype(T<U>::foo) x...);
|
||||
// };
|
||||
Out << "_SUBSTPACK_";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::InjectedClassName:
|
||||
mangleSourceName(cast<InjectedClassNameType>(type)->getDecl()
|
||||
->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::DependentName:
|
||||
mangleSourceName(cast<DependentNameType>(type)->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::DependentTemplateSpecialization: {
|
||||
const DependentTemplateSpecializationType *tst
|
||||
= cast<DependentTemplateSpecializationType>(type);
|
||||
mangleSourceName(tst->getIdentifier());
|
||||
mangleTemplateArgs(tst->getArgs(), tst->getNumArgs());
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NestedNameSpecifier::Identifier:
|
||||
// Member expressions can have these without prefixes.
|
||||
if (qualifier->getPrefix()) {
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup,
|
||||
if (qualifier->getPrefix())
|
||||
mangleUnresolvedPrefix(qualifier->getPrefix(),
|
||||
/*recursive*/ true);
|
||||
} else if (firstQualifierLookup) {
|
||||
|
||||
// Try to make a proper qualifier out of the lookup result, and
|
||||
// then just recurse on that.
|
||||
NestedNameSpecifier *newQualifier;
|
||||
if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) {
|
||||
QualType type = getASTContext().getTypeDeclType(typeDecl);
|
||||
|
||||
// Pretend we had a different nested name specifier.
|
||||
newQualifier = NestedNameSpecifier::Create(getASTContext(),
|
||||
/*prefix*/ nullptr,
|
||||
/*template*/ false,
|
||||
type.getTypePtr());
|
||||
} else if (NamespaceDecl *nspace =
|
||||
dyn_cast<NamespaceDecl>(firstQualifierLookup)) {
|
||||
newQualifier = NestedNameSpecifier::Create(getASTContext(),
|
||||
/*prefix*/ nullptr,
|
||||
nspace);
|
||||
} else if (NamespaceAliasDecl *alias =
|
||||
dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) {
|
||||
newQualifier = NestedNameSpecifier::Create(getASTContext(),
|
||||
/*prefix*/ nullptr,
|
||||
alias);
|
||||
} else {
|
||||
// No sensible mangling to do here.
|
||||
newQualifier = nullptr;
|
||||
}
|
||||
|
||||
if (newQualifier)
|
||||
return mangleUnresolvedPrefix(newQualifier, /*lookup*/ nullptr,
|
||||
recursive);
|
||||
|
||||
} else {
|
||||
else
|
||||
Out << "sr";
|
||||
}
|
||||
|
||||
mangleSourceName(qualifier->getAsIdentifier());
|
||||
break;
|
||||
|
@ -1058,10 +889,9 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
|
|||
/// Mangle an unresolved-name, which is generally used for names which
|
||||
/// weren't resolved to specific entities.
|
||||
void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
|
||||
NamedDecl *firstQualifierLookup,
|
||||
DeclarationName name,
|
||||
unsigned knownArity) {
|
||||
if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup);
|
||||
if (qualifier) mangleUnresolvedPrefix(qualifier);
|
||||
switch (name.getNameKind()) {
|
||||
// <base-unresolved-name> ::= <simple-id>
|
||||
case DeclarationName::Identifier:
|
||||
|
@ -1070,7 +900,7 @@ void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier,
|
|||
// <base-unresolved-name> ::= dn <destructor-name>
|
||||
case DeclarationName::CXXDestructorName:
|
||||
Out << "dn";
|
||||
mangleDestructorName(name.getCXXNameType());
|
||||
mangleUnresolvedTypeOrSimpleId(name.getCXXNameType());
|
||||
break;
|
||||
// <base-unresolved-name> ::= on <operator-name>
|
||||
case DeclarationName::CXXConversionFunctionName:
|
||||
|
@ -1648,29 +1478,149 @@ void CXXNameMangler::mangleType(TemplateName TN) {
|
|||
addSubstitution(TN);
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleDestructorName(QualType DestroyedType) {
|
||||
// <destructor-name> ::= <unresolved-type>
|
||||
// ::= <simple-id>
|
||||
if (const auto *TST = DestroyedType->getAs<TemplateSpecializationType>()) {
|
||||
bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
|
||||
StringRef Prefix) {
|
||||
// Only certain other types are valid as prefixes; enumerate them.
|
||||
switch (Ty->getTypeClass()) {
|
||||
case Type::Builtin:
|
||||
case Type::Complex:
|
||||
case Type::Adjusted:
|
||||
case Type::Decayed:
|
||||
case Type::Pointer:
|
||||
case Type::BlockPointer:
|
||||
case Type::LValueReference:
|
||||
case Type::RValueReference:
|
||||
case Type::MemberPointer:
|
||||
case Type::ConstantArray:
|
||||
case Type::IncompleteArray:
|
||||
case Type::VariableArray:
|
||||
case Type::DependentSizedArray:
|
||||
case Type::DependentSizedExtVector:
|
||||
case Type::Vector:
|
||||
case Type::ExtVector:
|
||||
case Type::FunctionProto:
|
||||
case Type::FunctionNoProto:
|
||||
case Type::Paren:
|
||||
case Type::Attributed:
|
||||
case Type::Auto:
|
||||
case Type::PackExpansion:
|
||||
case Type::ObjCObject:
|
||||
case Type::ObjCInterface:
|
||||
case Type::ObjCObjectPointer:
|
||||
case Type::Atomic:
|
||||
llvm_unreachable("type is illegal as a nested name specifier");
|
||||
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
// FIXME: not clear how to mangle this!
|
||||
// template <class T...> class A {
|
||||
// template <class U...> void foo(decltype(T::foo(U())) x...);
|
||||
// };
|
||||
Out << "_SUBSTPACK_";
|
||||
break;
|
||||
|
||||
// <unresolved-type> ::= <template-param>
|
||||
// ::= <decltype>
|
||||
// ::= <template-template-param> <template-args>
|
||||
// (this last is not official yet)
|
||||
case Type::TypeOfExpr:
|
||||
case Type::TypeOf:
|
||||
case Type::Decltype:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::UnaryTransform:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
unresolvedType:
|
||||
// Some callers want a prefix before the mangled type.
|
||||
Out << Prefix;
|
||||
|
||||
// This seems to do everything we want. It's not really
|
||||
// sanctioned for a substituted template parameter, though.
|
||||
mangleType(Ty);
|
||||
|
||||
// We never want to print 'E' directly after an unresolved-type,
|
||||
// so we return directly.
|
||||
return true;
|
||||
|
||||
case Type::Typedef:
|
||||
mangleSourceName(cast<TypedefType>(Ty)->getDecl()->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::UnresolvedUsing:
|
||||
mangleSourceName(
|
||||
cast<UnresolvedUsingType>(Ty)->getDecl()->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::Enum:
|
||||
case Type::Record:
|
||||
mangleSourceName(cast<TagType>(Ty)->getDecl()->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::TemplateSpecialization: {
|
||||
const TemplateSpecializationType *TST =
|
||||
cast<TemplateSpecializationType>(Ty);
|
||||
TemplateName TN = TST->getTemplateName();
|
||||
const auto *TD = TN.getAsTemplateDecl();
|
||||
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD)) {
|
||||
// Proposed to cxx-abi-dev on 2015-02-17.
|
||||
mangleTemplateParameter(TTP->getIndex());
|
||||
} else {
|
||||
mangleUnscopedName(TD->getTemplatedDecl());
|
||||
switch (TN.getKind()) {
|
||||
case TemplateName::Template:
|
||||
case TemplateName::QualifiedTemplate: {
|
||||
TemplateDecl *TD = TN.getAsTemplateDecl();
|
||||
|
||||
// If the base is a template template parameter, this is an
|
||||
// unresolved type.
|
||||
assert(TD && "no template for template specialization type");
|
||||
if (isa<TemplateTemplateParmDecl>(TD))
|
||||
goto unresolvedType;
|
||||
|
||||
mangleSourceName(TD->getIdentifier());
|
||||
break;
|
||||
}
|
||||
|
||||
case TemplateName::OverloadedTemplate:
|
||||
case TemplateName::DependentTemplate:
|
||||
llvm_unreachable("invalid base for a template specialization type");
|
||||
|
||||
case TemplateName::SubstTemplateTemplateParm: {
|
||||
SubstTemplateTemplateParmStorage *subst =
|
||||
TN.getAsSubstTemplateTemplateParm();
|
||||
mangleExistingSubstitution(subst->getReplacement());
|
||||
break;
|
||||
}
|
||||
|
||||
case TemplateName::SubstTemplateTemplateParmPack: {
|
||||
// FIXME: not clear how to mangle this!
|
||||
// template <template <class U> class T...> class A {
|
||||
// template <class U...> void foo(decltype(T<U>::foo) x...);
|
||||
// };
|
||||
Out << "_SUBSTPACK_";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
|
||||
} else if (const auto *DTST =
|
||||
DestroyedType->getAs<DependentTemplateSpecializationType>()) {
|
||||
const IdentifierInfo *II = DTST->getIdentifier();
|
||||
mangleSourceName(II);
|
||||
mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
|
||||
} else {
|
||||
// We use the QualType mangle type variant here because it handles
|
||||
// substitutions.
|
||||
mangleType(DestroyedType);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::InjectedClassName:
|
||||
mangleSourceName(
|
||||
cast<InjectedClassNameType>(Ty)->getDecl()->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::DependentName:
|
||||
mangleSourceName(cast<DependentNameType>(Ty)->getIdentifier());
|
||||
break;
|
||||
|
||||
case Type::DependentTemplateSpecialization: {
|
||||
const DependentTemplateSpecializationType *DTST =
|
||||
cast<DependentTemplateSpecializationType>(Ty);
|
||||
mangleSourceName(DTST->getIdentifier());
|
||||
mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs());
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::Elaborated:
|
||||
return mangleUnresolvedTypeOrSimpleId(
|
||||
cast<ElaboratedType>(Ty)->getNamedType(), Prefix);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleOperatorName(DeclarationName Name, unsigned Arity) {
|
||||
|
@ -2636,7 +2586,7 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base,
|
|||
// ::= pt <expression> <unresolved-name>
|
||||
if (base)
|
||||
mangleMemberExprBase(base, isArrow);
|
||||
mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity);
|
||||
mangleUnresolvedName(qualifier, member, arity);
|
||||
}
|
||||
|
||||
/// Look at the callee of the given call expression and determine if
|
||||
|
@ -2894,12 +2844,26 @@ recurse:
|
|||
const auto *PDE = cast<CXXPseudoDestructorExpr>(E);
|
||||
if (const Expr *Base = PDE->getBase())
|
||||
mangleMemberExprBase(Base, PDE->isArrow());
|
||||
if (NestedNameSpecifier *Qualifier = PDE->getQualifier())
|
||||
mangleUnresolvedPrefix(Qualifier, /*FirstQualifierLookup=*/nullptr);
|
||||
NestedNameSpecifier *Qualifier = PDE->getQualifier();
|
||||
QualType ScopeType;
|
||||
if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) {
|
||||
if (Qualifier) {
|
||||
mangleUnresolvedPrefix(Qualifier,
|
||||
/*Recursive=*/true);
|
||||
mangleUnresolvedTypeOrSimpleId(ScopeInfo->getType());
|
||||
Out << 'E';
|
||||
} else {
|
||||
Out << "sr";
|
||||
if (!mangleUnresolvedTypeOrSimpleId(ScopeInfo->getType()))
|
||||
Out << 'E';
|
||||
}
|
||||
} else if (Qualifier) {
|
||||
mangleUnresolvedPrefix(Qualifier);
|
||||
}
|
||||
// <base-unresolved-name> ::= dn <destructor-name>
|
||||
Out << "dn";
|
||||
QualType DestroyedType = PDE->getDestroyedType();
|
||||
mangleDestructorName(DestroyedType);
|
||||
mangleUnresolvedTypeOrSimpleId(DestroyedType);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2934,7 +2898,7 @@ recurse:
|
|||
|
||||
case Expr::UnresolvedLookupExprClass: {
|
||||
const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
|
||||
mangleUnresolvedName(ULE->getQualifier(), nullptr, ULE->getName(), Arity);
|
||||
mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity);
|
||||
|
||||
// All the <unresolved-name> productions end in a
|
||||
// base-unresolved-name, where <template-args> are just tacked
|
||||
|
@ -3248,8 +3212,7 @@ recurse:
|
|||
|
||||
case Expr::DependentScopeDeclRefExprClass: {
|
||||
const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
|
||||
mangleUnresolvedName(DRE->getQualifier(), nullptr, DRE->getDeclName(),
|
||||
Arity);
|
||||
mangleUnresolvedName(DRE->getQualifier(), DRE->getDeclName(), Arity);
|
||||
|
||||
// All the <unresolved-name> productions end in a
|
||||
// base-unresolved-name, where <template-args> are just tacked
|
||||
|
|
|
@ -1024,6 +1024,12 @@ namespace test51 {
|
|||
template void fun<S1<int> >();
|
||||
// CHECK-LABEL: @_ZN6test513funI2S1IiEEEDTcldtcvT__EdnS3_EEv
|
||||
|
||||
enum E {};
|
||||
template <typename T>
|
||||
struct X {
|
||||
struct Y {};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
decltype(S1<T>().~S1<T>()) fun1() {};
|
||||
template <typename U, typename T>
|
||||
|
@ -1036,6 +1042,10 @@ namespace test51 {
|
|||
decltype(S1<int>().~S1<T>()) fun5(){};
|
||||
template <template <typename T> class U>
|
||||
decltype(S1<int>().~U<int>()) fun6(){};
|
||||
template <typename T>
|
||||
decltype(E().E::~T()) fun7() {}
|
||||
template <template <typename> class U>
|
||||
decltype(X<int>::Y().U<int>::Y::~Y()) fun8() {}
|
||||
template void fun1<int>();
|
||||
// CHECK-LABEL: @_ZN6test514fun1IiEEDTcldtcv2S1IT_E_Edn2S1IS2_EEEv
|
||||
template void fun2<S1<int>, int>();
|
||||
|
@ -1045,6 +1055,10 @@ namespace test51 {
|
|||
template void fun4<int>();
|
||||
// CHECK-LABEL: @_ZN6test514fun4IiEEDTcmcldtcv2S1IT_E_Edn2S1IS2_EEcldtcvS3__Edn2S1IS2_EEEv
|
||||
template void fun5<int>();
|
||||
// CHECK-LABEL: @_ZN6test514fun6I2S1EEDTcldtcvS1_IiE_EdnT_IiEEEv
|
||||
// CHECK-LABEL: @_ZN6test514fun5IiEEDTcldtcv2S1IiE_Edn2S1IT_EEEv
|
||||
template void fun6<S1>();
|
||||
// CHECK-LABEL: @_ZN6test514fun6I2S1EEDTcldtcvS1_IiE_EdnT_IiEEEv
|
||||
template void fun7<E>();
|
||||
// CHECK-LABEL: @_ZN6test514fun7INS_1EEEEDTcldtcvS1__Esr1EEdnT_EEv
|
||||
template void fun8<X>();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue