зеркало из https://github.com/microsoft/clang.git
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:
Родитель
b1bdc6232d
Коммит
a2e7dd2f4a
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче