Use CXXPseudoDestructorExpr as the stored representation for dependent

expressions that look like pseudo-destructors, e.g.,

  p->T::~T()

where p has dependent type.

At template instantiate time, we determine whether we actually have a
pseudo-destructor or a member access, and funnel down to the
appropriate routine in Sema.

Fixes PR6380.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97092 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-02-25 01:56:36 +00:00
Родитель b1bdc6232d
Коммит a2e7dd2f4a
8 изменённых файлов: 197 добавлений и 218 удалений

Просмотреть файл

@ -997,6 +997,35 @@ public:
virtual child_iterator child_end();
};
/// \brief Structure used to store the type being destroyed by a
/// pseudo-destructor expression.
class PseudoDestructorTypeStorage {
/// \brief Either the type source information or the name of the type, if
/// it couldn't be resolved due to type-dependence.
llvm::PointerUnion<TypeSourceInfo *, IdentifierInfo *> Type;
/// \brief The starting source location of the pseudo-destructor type.
SourceLocation Location;
public:
PseudoDestructorTypeStorage() { }
PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc)
: Type(II), Location(Loc) { }
PseudoDestructorTypeStorage(TypeSourceInfo *Info);
TypeSourceInfo *getTypeSourceInfo() const {
return Type.dyn_cast<TypeSourceInfo *>();
}
IdentifierInfo *getIdentifier() const {
return Type.dyn_cast<IdentifierInfo *>();
}
SourceLocation getLocation() const { return Location; }
};
/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]).
///
/// A pseudo-destructor is an expression that looks like a member access to a
@ -1050,8 +1079,9 @@ class CXXPseudoDestructorExpr : public Expr {
/// \brief The location of the '~'.
SourceLocation TildeLoc;
/// \brief The type being destroyed.
TypeSourceInfo *DestroyedType;
/// \brief The type being destroyed, or its name if we were unable to
/// resolve the name.
PseudoDestructorTypeStorage DestroyedType;
public:
CXXPseudoDestructorExpr(ASTContext &Context,
@ -1061,14 +1091,15 @@ public:
TypeSourceInfo *ScopeType,
SourceLocation ColonColonLoc,
SourceLocation TildeLoc,
TypeSourceInfo *DestroyedType)
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
false, 0, false,
false, 0, 0, false,
CC_Default)),
/*isTypeDependent=*/(Base->isTypeDependent() ||
DestroyedType->getType()->isDependentType()),
(DestroyedType.getTypeSourceInfo() &&
DestroyedType.getTypeSourceInfo()->getType()->isDependentType())),
/*isValueDependent=*/Base->isValueDependent()),
Base(static_cast<Stmt *>(Base)), IsArrow(isArrow),
OperatorLoc(OperatorLoc), Qualifier(Qualifier),
@ -1120,12 +1151,31 @@ public:
/// \brief Retrieve the location of the '~'.
SourceLocation getTildeLoc() const { return TildeLoc; }
/// \brief Retrieve the type that is being destroyed.
QualType getDestroyedType() const { return DestroyedType->getType(); }
/// \brief Retrieve the source location information for the type
/// being destroyed.
TypeSourceInfo *getDestroyedTypeInfo() const { return DestroyedType; }
///
/// This type-source information is available for non-dependent
/// pseudo-destructor expressions and some dependent pseudo-destructor
/// expressions. Returns NULL if we only have the identifier for a
/// dependent pseudo-destructor expression.
TypeSourceInfo *getDestroyedTypeInfo() const {
return DestroyedType.getTypeSourceInfo();
}
/// \brief In a dependent pseudo-destructor expression for which we do not
/// have full type information on the destroyed type, provides the name
/// of the destroyed type.
IdentifierInfo *getDestroyedTypeIdentifier() const {
return DestroyedType.getIdentifier();
}
/// \brief Retrieve the type being destroyed.
QualType getDestroyedType() const;
/// \brief Retrieve the starting location of the type being destroyed.
SourceLocation getDestroyedTypeLoc() const {
return DestroyedType.getLocation();
}
virtual SourceRange getSourceRange() const;

Просмотреть файл

@ -122,9 +122,24 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
return &Base + 1;
}
PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
: Type(Info)
{
Location = Info->getTypeLoc().getSourceRange().getBegin();
}
QualType CXXPseudoDestructorExpr::getDestroyedType() const {
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
return TInfo->getType();
return QualType();
}
SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
return SourceRange(Base->getLocStart(),
DestroyedType->getTypeLoc().getSourceRange().getEnd());
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
End = TInfo->getTypeLoc().getSourceRange().getEnd();
return SourceRange(Base->getLocStart(), End);
}

Просмотреть файл

@ -1120,7 +1120,10 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->getQualifier()->print(OS, Policy);
std::string TypeS;
E->getDestroyedType().getAsStringInternal(TypeS, Policy);
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
OS << II->getName();
else
E->getDestroyedType().getAsStringInternal(TypeS, Policy);
OS << TypeS;
}

Просмотреть файл

@ -95,6 +95,7 @@ namespace clang {
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCContainerDecl;
class PseudoDestructorTypeStorage;
class FunctionProtoType;
class CXXBasePath;
class CXXBasePaths;
@ -2188,20 +2189,9 @@ public:
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
TypeSourceInfo *DestroyedType,
PseudoDestructorTypeStorage DestroyedType,
bool HasTrailingLParen);
OwningExprResult ActOnDependentPseudoDestructorExpr(Scope *S,
ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen);
virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,

Просмотреть файл

@ -161,7 +161,7 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
Found.clear();
if (Step == 0 && LookupCtx)
LookupQualifiedName(Found, LookupCtx);
else if (Step == 1 && LookInScope)
else if (Step == 1 && LookInScope && S)
LookupName(Found, S);
else
continue;
@ -2441,9 +2441,9 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
TypeSourceInfo *ScopeTypeInfo,
SourceLocation CCLoc,
SourceLocation TildeLoc,
TypeSourceInfo *DestructedTypeInfo,
PseudoDestructorTypeStorage Destructed,
bool HasTrailingLParen) {
assert(DestructedTypeInfo && "No destructed type in pseudo-destructor expr?");
TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
// C++ [expr.pseudo]p2:
// The left-hand side of the dot operator shall be of scalar type. The
@ -2475,21 +2475,24 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
// C++ [expr.pseudo]p2:
// [...] The cv-unqualified versions of the object type and of the type
// designated by the pseudo-destructor-name shall be the same type.
QualType DestructedType = DestructedTypeInfo->getType();
SourceLocation DestructedTypeStart
= DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << DestructedType << BaseE->getSourceRange()
<< DestructedTypeInfo->getTypeLoc().getSourceRange();
// Recover by
DestructedType = ObjectType;
DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
DestructedTypeStart);
if (DestructedTypeInfo) {
QualType DestructedType = DestructedTypeInfo->getType();
SourceLocation DestructedTypeStart
= DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
<< ObjectType << DestructedType << BaseE->getSourceRange()
<< DestructedTypeInfo->getTypeLoc().getSourceRange();
// Recover by setting the destructed type to the object type.
DestructedType = ObjectType;
DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
DestructedTypeStart);
Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
}
}
// C++ [expr.pseudo]p2:
// [...] Furthermore, the two type-names in a pseudo-destructor-name of the
// form
@ -2522,148 +2525,12 @@ Sema::OwningExprResult Sema::BuildPseudoDestructorExpr(ExprArg Base,
ScopeTypeInfo,
CCLoc,
TildeLoc,
DestructedTypeInfo));
Destructed));
if (HasTrailingLParen)
return move(Result);
return DiagnoseDtorReference(
DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(),
move(Result));
}
Sema::OwningExprResult
Sema::ActOnDependentPseudoDestructorExpr(Scope *S,
ExprArg Base,
SourceLocation OpLoc,
tok::TokenKind OpKind,
const CXXScopeSpec &SS,
UnqualifiedId &FirstTypeName,
SourceLocation CCLoc,
SourceLocation TildeLoc,
UnqualifiedId &SecondTypeName,
bool HasTrailingLParen) {
Expr *BaseE = (Expr *)Base.get();
QualType ObjectType = BaseE->getType();
assert(ObjectType->isDependentType());
// The nested-name-specifier provided by the parser, then extended
// by the "type-name ::" in the pseudo-destructor-name, if present.
CXXScopeSpec ExtendedSS = SS;
if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
FirstTypeName.Identifier) {
// We have a pseudo-destructor with a "type-name ::".
// FIXME: As a temporary hack, we go ahead and resolve this to part of
// a nested-name-specifier.
if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
// Resolve the identifier to a nested-name-specifier.
CXXScopeTy *FinalScope
= ActOnCXXNestedNameSpecifier(S, SS,
FirstTypeName.StartLocation,
CCLoc,
*FirstTypeName.Identifier,
true,
ObjectType.getAsOpaquePtr(),
false);
if (SS.getBeginLoc().isInvalid())
ExtendedSS.setBeginLoc(FirstTypeName.StartLocation);
ExtendedSS.setEndLoc(CCLoc);
ExtendedSS.setScopeRep(FinalScope);
} else {
// Resolve the template-id to a type, and that to a
// nested-name-specifier.
TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc);
if (!T.isInvalid()) {
CXXScopeTy *FinalScope
= ActOnCXXNestedNameSpecifier(S, SS, T.get(),
SourceRange(TemplateId->TemplateNameLoc,
TemplateId->RAngleLoc),
CCLoc,
true);
if (SS.getBeginLoc().isInvalid())
ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc);
ExtendedSS.setEndLoc(CCLoc);
ExtendedSS.setScopeRep(FinalScope);
}
}
}
// Produce a destructor name based on the second type-name (which
// follows the tilde).
TypeTy *DestructedType;
SourceLocation EndLoc;
if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
const CXXScopeSpec *LookupSS = &SS;
bool isDependent = isDependentScopeSpecifier(ExtendedSS);
if (isDependent || computeDeclContext(ExtendedSS))
LookupSS = &ExtendedSS;
DestructedType = getTypeName(*SecondTypeName.Identifier,
SecondTypeName.StartLocation,
S, LookupSS, true, ObjectType.getTypePtr());
if (!DestructedType && isDependent) {
// We didn't find our type, but that's okay: it's dependent
// anyway.
// FIXME: We should not be building a typename type here!
NestedNameSpecifier *NNS = 0;
SourceRange Range;
if (SS.isSet()) {
NNS = (NestedNameSpecifier *)ExtendedSS.getScopeRep();
Range = SourceRange(ExtendedSS.getRange().getBegin(),
SecondTypeName.StartLocation);
} else {
NNS = NestedNameSpecifier::Create(Context, SecondTypeName.Identifier);
Range = SourceRange(SecondTypeName.StartLocation);
}
DestructedType = CheckTypenameType(NNS, *SecondTypeName.Identifier,
Range).getAsOpaquePtr();
if (!DestructedType)
return ExprError();
}
if (!DestructedType) {
// FIXME: Crummy diagnostic.
Diag(SecondTypeName.StartLocation, diag::err_destructor_class_name);
return ExprError();
}
EndLoc = SecondTypeName.EndLocation;
} else {
// Resolve the template-id to a type, and that to a
// nested-name-specifier.
TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
ASTTemplateArgsPtr TemplateArgsPtr(*this,
TemplateId->getTemplateArgs(),
TemplateId->NumArgs);
EndLoc = TemplateId->RAngleLoc;
TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
TemplateId->TemplateNameLoc,
TemplateId->LAngleLoc,
TemplateArgsPtr,
TemplateId->RAngleLoc);
if (T.isInvalid() || !T.get())
return ExprError();
DestructedType = T.get();
}
// Form a (possibly fake) destructor name and let the member access
// expression code deal with this.
// FIXME: Don't do this! It's totally broken!
UnqualifiedId Destructor;
Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc);
return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS,
Destructor, DeclPtrTy(), HasTrailingLParen);
return DiagnoseDtorReference(Destructed.getLocation(), move(Result));
}
Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
@ -2683,11 +2550,6 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
"Invalid second type name in pseudo-destructor");
Expr *BaseE = (Expr *)Base.get();
if (BaseE->isTypeDependent())
return ActOnDependentPseudoDestructorExpr(S, move(Base), OpLoc, OpKind,
SS, FirstTypeName, CCLoc,
TildeLoc, SecondTypeName,
HasTrailingLParen);
// C++ [expr.pseudo]p2:
// The left-hand side of the dot operator shall be of scalar type. The
@ -2697,27 +2559,46 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
if (OpKind == tok::arrow) {
if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
ObjectType = Ptr->getPointeeType();
} else if (!BaseE->isTypeDependent()) {
} else if (!ObjectType->isDependentType()) {
// The user wrote "p->" when she probably meant "p."; fix it.
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< ObjectType << true
<< CodeModificationHint::CreateReplacement(OpLoc, ".");
<< ObjectType << true
<< CodeModificationHint::CreateReplacement(OpLoc, ".");
if (isSFINAEContext())
return ExprError();
OpKind = tok::period;
}
}
// Compute the object type that we should use for name lookup purposes. Only
// record types and dependent types matter.
void *ObjectTypePtrForLookup = 0;
if (!SS.isSet()) {
ObjectTypePtrForLookup = (void *)ObjectType->getAs<RecordType>();
if (!ObjectTypePtrForLookup && ObjectType->isDependentType())
ObjectTypePtrForLookup = Context.DependentTy.getAsOpaquePtr();
}
// Convert the name of the type being destructed (following the ~) into a
// type (with source-location information).
QualType DestructedType;
TypeSourceInfo *DestructedTypeInfo = 0;
PseudoDestructorTypeStorage Destructed;
if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
TypeTy *T = getTypeName(*SecondTypeName.Identifier,
SecondTypeName.StartLocation,
S, &SS);
if (!T) {
S, &SS, true, ObjectTypePtrForLookup);
if (!T &&
((SS.isSet() && !computeDeclContext(SS, false)) ||
(!SS.isSet() && ObjectType->isDependentType()))) {
// The name of the type being destroyed is a dependent name, and we
// couldn't find anything useful in scope. Just store the identifier and
// it's location, and we'll perform (qualified) name lookup again at
// template instantiation time.
Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier,
SecondTypeName.StartLocation);
} else if (!T) {
Diag(SecondTypeName.StartLocation,
diag::err_pseudo_dtor_destructor_non_type)
<< SecondTypeName.Identifier << ObjectType;
@ -2748,9 +2629,12 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
// If we've performed some kind of recovery, (re-)build the type source
// information.
if (!DestructedTypeInfo)
DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType,
if (!DestructedType.isNull()) {
if (!DestructedTypeInfo)
DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType,
SecondTypeName.StartLocation);
Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
}
// Convert the name of the scope type (the type prior to '::') into a type.
TypeSourceInfo *ScopeTypeInfo = 0;
@ -2760,7 +2644,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
TypeTy *T = getTypeName(*FirstTypeName.Identifier,
FirstTypeName.StartLocation,
S, &SS);
S, &SS, false, ObjectTypePtrForLookup);
if (!T) {
Diag(FirstTypeName.StartLocation,
diag::err_pseudo_dtor_destructor_non_type)
@ -2799,7 +2683,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS,
ScopeTypeInfo, CCLoc, TildeLoc,
DestructedTypeInfo, HasTrailingLParen);
Destructed, HasTrailingLParen);
}
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,

Просмотреть файл

@ -884,12 +884,12 @@ public:
OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base,
SourceLocation OperatorLoc,
bool isArrow,
NestedNameSpecifier *Qualifier,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
TypeSourceInfo *DestroyedType);
PseudoDestructorTypeStorage Destroyed);
/// \brief Build a new unary operator expression.
///
@ -4671,34 +4671,67 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
if (Base.isInvalid())
return SemaRef.ExprError();
Sema::TypeTy *ObjectTypePtr = 0;
bool MayBePseudoDestructor = false;
Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
E->getOperatorLoc(),
E->isArrow()? tok::arrow : tok::period,
ObjectTypePtr,
MayBePseudoDestructor);
if (Base.isInvalid())
return SemaRef.ExprError();
QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
NestedNameSpecifier *Qualifier
= getDerived().TransformNestedNameSpecifier(E->getQualifier(),
E->getQualifierRange(),
true);
true,
ObjectType);
if (E->getQualifier() && !Qualifier)
return SemaRef.ExprError();
// FIXME: Object type!
TypeSourceInfo *DestroyedTypeInfo
= getDerived().TransformType(E->getDestroyedTypeInfo());
if (!DestroyedTypeInfo)
return SemaRef.ExprError();
PseudoDestructorTypeStorage Destroyed;
if (E->getDestroyedTypeInfo()) {
TypeSourceInfo *DestroyedTypeInfo
= getDerived().TransformType(E->getDestroyedTypeInfo(), ObjectType);
if (!DestroyedTypeInfo)
return SemaRef.ExprError();
Destroyed = DestroyedTypeInfo;
} else if (ObjectType->isDependentType()) {
// We aren't likely to be able to resolve the identifier down to a type
// now anyway, so just retain the identifier.
Destroyed = PseudoDestructorTypeStorage(E->getDestroyedTypeIdentifier(),
E->getDestroyedTypeLoc());
} else {
// Look for a destructor known with the given name.
CXXScopeSpec SS;
if (Qualifier) {
SS.setScopeRep(Qualifier);
SS.setRange(E->getQualifierRange());
}
Sema::TypeTy *T = SemaRef.getDestructorName(E->getTildeLoc(),
*E->getDestroyedTypeIdentifier(),
E->getDestroyedTypeLoc(),
/*Scope=*/0,
SS, ObjectTypePtr,
false);
if (!T)
return SemaRef.ExprError();
Destroyed
= SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.GetTypeFromParser(T),
E->getDestroyedTypeLoc());
}
// FIXME: Object type!
TypeSourceInfo *ScopeTypeInfo = 0;
if (E->getScopeTypeInfo()) {
ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo());
ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo(),
ObjectType);
if (!ScopeTypeInfo)
return SemaRef.ExprError();
}
if (!getDerived().AlwaysRebuild() &&
Base.get() == E->getBase() &&
Qualifier == E->getQualifier() &&
ScopeTypeInfo == E->getScopeTypeInfo() &&
DestroyedTypeInfo == E->getDestroyedTypeInfo())
return SemaRef.Owned(E->Retain());
return getDerived().RebuildCXXPseudoDestructorExpr(move(Base),
E->getOperatorLoc(),
E->isArrow(),
@ -4707,7 +4740,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
ScopeTypeInfo,
E->getColonColonLoc(),
E->getTildeLoc(),
DestroyedTypeInfo);
Destroyed);
}
template<typename Derived>
@ -5758,7 +5791,7 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(ExprArg Base,
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
TypeSourceInfo *DestroyedType) {
PseudoDestructorTypeStorage Destroyed) {
CXXScopeSpec SS;
if (Qualifier) {
SS.setRange(QualifierRange);
@ -5767,18 +5800,19 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(ExprArg Base,
Expr *BaseE = (Expr *)Base.get();
QualType BaseType = BaseE->getType();
if (BaseE->isTypeDependent() ||
if (BaseE->isTypeDependent() || Destroyed.getIdentifier() ||
(!isArrow && !BaseType->getAs<RecordType>()) ||
(isArrow && BaseType->getAs<PointerType>() &&
!BaseType->getAs<PointerType>()->getAs<RecordType>())) {
!BaseType->getAs<PointerType>()->getPointeeType()->getAs<RecordType>())){
// This pseudo-destructor expression is still a pseudo-destructor.
return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc,
isArrow? tok::arrow : tok::period,
SS, ScopeType, CCLoc, TildeLoc,
DestroyedType,
Destroyed,
/*FIXME?*/true);
}
TypeSourceInfo *DestroyedType = Destroyed.getTypeSourceInfo();
DeclarationName Name
= SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(DestroyedType->getType()));
@ -5788,8 +5822,7 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(ExprArg Base,
return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
OperatorLoc, isArrow,
SS, /*FIXME: FirstQualifier*/ 0,
Name,
DestroyedType->getTypeLoc().getSourceRange().getBegin(),
Name, Destroyed.getLocation(),
/*TemplateArgs*/ 0);
}

Просмотреть файл

@ -25,6 +25,8 @@ namespace PR6152 {
void X<T>::f() {
Y<T> *y;
y->template Y<T>::~Y();
y->template Y<T>::~Y<T>();
y->~Y();
}
template struct X<int>;

Просмотреть файл

@ -63,11 +63,13 @@ void test_convert(X2 x2) {
template<typename T>
void destruct(T* ptr) {
ptr->~T();
ptr->T::~T();
}
template<typename T>
void destruct_intptr(int *ip) {
ip->~T();
ip->T::~T();
}
void test_destruct(X2 *x2p, int *ip) {