forked from OSchip/llvm-project
ActOnPseudoDestructorExpr now performs all semantic analysis for
pseudo-destructor expressions, and builds the CXXPseudoDestructorExpr node directly. Currently, this only affects pseudo-destructor expressions when they are parsed, but not after template instantiation. That's coming next... Improve parsing of pseudo-destructor-names. When parsing the nested-name-specifier and we hit the sequence of tokens X :: ~, query the actual module to determine whether X is a type-name (in which case the X :: is part of the pseudo-destructor-name but not the nested-name-specifier) or not (in which case the X :: is part of the nested-name-specifier). llvm-svn: 97058
This commit is contained in:
parent
02ec121de8
commit
0d5b0a1e5e
|
@ -2078,7 +2078,12 @@ def err_pseudo_dtor_call_with_args : Error<
|
|||
def err_dtor_expr_without_call : Error<
|
||||
"%select{destructor reference|pseudo-destructor expression}0 must be "
|
||||
"called immediately with '()'">;
|
||||
|
||||
def err_pseudo_dtor_destructor_non_type : Error<
|
||||
"%0 does not refer to a type name in pseudo-destructor expression; expected "
|
||||
"the name of type %1">;
|
||||
def err_pseudo_dtor_template : Error<
|
||||
"specialization of template %0 does not refer to a scalar type in pseudo-"
|
||||
"destructor expression">;
|
||||
def err_invalid_use_of_function_type : Error<
|
||||
"a function type is not allowed here">;
|
||||
def err_invalid_use_of_array_type : Error<"an array type is not allowed here">;
|
||||
|
|
|
@ -327,13 +327,26 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/// \brief Determine whether the given name refers to a non-type nested name
|
||||
/// specifier, e.g., the name of a namespace or namespace alias.
|
||||
///
|
||||
/// This actual is used in the parsing of pseudo-destructor names to
|
||||
/// distinguish a nested-name-specifier and a "type-name ::" when we
|
||||
/// see the token sequence "X :: ~".
|
||||
virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
|
||||
SourceLocation IdLoc,
|
||||
IdentifierInfo &II,
|
||||
TypeTy *ObjectType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
|
||||
/// global scope ('::').
|
||||
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
|
||||
SourceLocation CCLoc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Parsed an identifier followed by '::' in a C++
|
||||
/// nested-name-specifier.
|
||||
///
|
||||
|
|
|
@ -240,7 +240,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
// If we get foo:bar, this is almost certainly a typo for foo::bar. Recover
|
||||
// and emit a fixit hint for it.
|
||||
if (Next.is(tok::colon) && !ColonIsSacred) {
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
|
||||
!Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(),
|
||||
II, ObjectType)) {
|
||||
*MayBePseudoDestructor = true;
|
||||
return HasScopeSpecifier;
|
||||
}
|
||||
|
@ -261,7 +263,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
|
|||
}
|
||||
|
||||
if (Next.is(tok::coloncolon)) {
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
|
||||
if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
|
||||
!Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(),
|
||||
II, ObjectType)) {
|
||||
*MayBePseudoDestructor = true;
|
||||
return HasScopeSpecifier;
|
||||
}
|
||||
|
|
|
@ -2178,6 +2178,20 @@ public:
|
|||
TypeTy *&ObjectType,
|
||||
bool &MayBePseudoDestructor);
|
||||
|
||||
OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc,
|
||||
ExprArg MemExpr);
|
||||
|
||||
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,
|
||||
|
@ -2187,7 +2201,7 @@ public:
|
|||
SourceLocation TildeLoc,
|
||||
UnqualifiedId &SecondTypeName,
|
||||
bool HasTrailingLParen);
|
||||
|
||||
|
||||
/// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
|
||||
/// non-empty, will create a new CXXExprWithTemporaries expression.
|
||||
/// Otherwise, just returs the passed in expression.
|
||||
|
@ -2215,7 +2229,11 @@ public:
|
|||
bool MayBePseudoDestructor = false);
|
||||
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
|
||||
|
||||
|
||||
virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
|
||||
SourceLocation IdLoc,
|
||||
IdentifierInfo &II,
|
||||
TypeTy *ObjectType);
|
||||
|
||||
CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
|
||||
const CXXScopeSpec &SS,
|
||||
SourceLocation IdLoc,
|
||||
|
|
|
@ -332,6 +332,54 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
|
||||
SourceLocation IdLoc,
|
||||
IdentifierInfo &II,
|
||||
TypeTy *ObjectTypePtr) {
|
||||
QualType ObjectType = GetTypeFromParser(ObjectTypePtr);
|
||||
LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName);
|
||||
|
||||
// Determine where to perform name lookup
|
||||
DeclContext *LookupCtx = 0;
|
||||
bool isDependent = false;
|
||||
if (!ObjectType.isNull()) {
|
||||
// This nested-name-specifier occurs in a member access expression, e.g.,
|
||||
// x->B::f, and we are looking into the type of the object.
|
||||
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
|
||||
LookupCtx = computeDeclContext(ObjectType);
|
||||
isDependent = ObjectType->isDependentType();
|
||||
} else if (SS.isSet()) {
|
||||
// This nested-name-specifier occurs after another nested-name-specifier,
|
||||
// so long into the context associated with the prior nested-name-specifier.
|
||||
LookupCtx = computeDeclContext(SS, false);
|
||||
isDependent = isDependentScopeSpecifier(SS);
|
||||
Found.setContextRange(SS.getRange());
|
||||
}
|
||||
|
||||
if (LookupCtx) {
|
||||
// Perform "qualified" name lookup into the declaration context we
|
||||
// computed, which is either the type of the base of a member access
|
||||
// expression or the declaration context associated with a prior
|
||||
// nested-name-specifier.
|
||||
|
||||
// The declaration context must be complete.
|
||||
if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
|
||||
return false;
|
||||
|
||||
LookupQualifiedName(Found, LookupCtx);
|
||||
} else if (isDependent) {
|
||||
return false;
|
||||
} else {
|
||||
LookupName(Found, S);
|
||||
}
|
||||
Found.suppressDiagnostics();
|
||||
|
||||
if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
|
||||
return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Build a new nested-name-specifier for "identifier::", as described
|
||||
/// by ActOnCXXNestedNameSpecifier.
|
||||
///
|
||||
|
|
|
@ -3178,23 +3178,6 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef,
|
||||
SourceLocation NameLoc,
|
||||
Sema::ExprArg MemExpr) {
|
||||
Expr *E = (Expr *) MemExpr.get();
|
||||
SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc);
|
||||
SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
|
||||
<< isa<CXXPseudoDestructorExpr>(E)
|
||||
<< CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
|
||||
|
||||
return SemaRef.ActOnCallExpr(/*Scope*/ 0,
|
||||
move(MemExpr),
|
||||
/*LPLoc*/ ExpectedLParenLoc,
|
||||
Sema::MultiExprArg(SemaRef, 0, 0),
|
||||
/*CommaLocs*/ 0,
|
||||
/*RPLoc*/ ExpectedLParenLoc);
|
||||
}
|
||||
|
||||
/// The main callback when the parser finds something like
|
||||
/// expression . [nested-name-specifier] identifier
|
||||
/// expression -> [nested-name-specifier] identifier
|
||||
|
@ -3265,7 +3248,7 @@ Sema::OwningExprResult Sema::ActOnMemberAccessExpr(Scope *S, ExprArg BaseArg,
|
|||
// call now.
|
||||
if (!HasTrailingLParen &&
|
||||
Id.getKind() == UnqualifiedId::IK_DestructorName)
|
||||
return DiagnoseDtorReference(*this, NameLoc, move(Result));
|
||||
return DiagnoseDtorReference(NameLoc, move(Result));
|
||||
|
||||
return move(Result);
|
||||
}
|
||||
|
|
|
@ -2410,31 +2410,41 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
return move(Base);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &FirstTypeName,
|
||||
SourceLocation CCLoc,
|
||||
SourceLocation TildeLoc,
|
||||
UnqualifiedId &SecondTypeName,
|
||||
bool HasTrailingLParen) {
|
||||
assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
|
||||
"Invalid first type name in pseudo-destructor");
|
||||
assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
|
||||
"Invalid second type name in pseudo-destructor");
|
||||
Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
|
||||
ExprArg MemExpr) {
|
||||
Expr *E = (Expr *) MemExpr.get();
|
||||
SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc);
|
||||
Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
|
||||
<< isa<CXXPseudoDestructorExpr>(E)
|
||||
<< CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
|
||||
|
||||
return ActOnCallExpr(/*Scope*/ 0,
|
||||
move(MemExpr),
|
||||
/*LPLoc*/ ExpectedLParenLoc,
|
||||
Sema::MultiExprArg(*this, 0, 0),
|
||||
/*CommaLocs*/ 0,
|
||||
/*RPLoc*/ ExpectedLParenLoc);
|
||||
}
|
||||
|
||||
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;
|
||||
if (BaseE->isTypeDependent())
|
||||
ObjectType = Context.DependentTy;
|
||||
|
||||
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 ::".
|
||||
|
@ -2443,13 +2453,13 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
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);
|
||||
= ActOnCXXNestedNameSpecifier(S, SS,
|
||||
FirstTypeName.StartLocation,
|
||||
CCLoc,
|
||||
*FirstTypeName.Identifier,
|
||||
true,
|
||||
ObjectType.getAsOpaquePtr(),
|
||||
false);
|
||||
if (SS.getBeginLoc().isInvalid())
|
||||
ExtendedSS.setBeginLoc(FirstTypeName.StartLocation);
|
||||
ExtendedSS.setEndLoc(CCLoc);
|
||||
|
@ -2468,11 +2478,11 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
TemplateId->RAngleLoc);
|
||||
if (!T.isInvalid()) {
|
||||
CXXScopeTy *FinalScope
|
||||
= ActOnCXXNestedNameSpecifier(S, SS, T.get(),
|
||||
SourceRange(TemplateId->TemplateNameLoc,
|
||||
TemplateId->RAngleLoc),
|
||||
CCLoc,
|
||||
true);
|
||||
= ActOnCXXNestedNameSpecifier(S, SS, T.get(),
|
||||
SourceRange(TemplateId->TemplateNameLoc,
|
||||
TemplateId->RAngleLoc),
|
||||
CCLoc,
|
||||
true);
|
||||
if (SS.getBeginLoc().isInvalid())
|
||||
ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc);
|
||||
ExtendedSS.setEndLoc(CCLoc);
|
||||
|
@ -2480,7 +2490,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Produce a destructor name based on the second type-name (which
|
||||
// follows the tilde).
|
||||
TypeTy *DestructedType;
|
||||
|
@ -2490,7 +2500,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
bool isDependent = isDependentScopeSpecifier(ExtendedSS);
|
||||
if (isDependent || computeDeclContext(ExtendedSS))
|
||||
LookupSS = &ExtendedSS;
|
||||
|
||||
|
||||
DestructedType = getTypeName(*SecondTypeName.Identifier,
|
||||
SecondTypeName.StartLocation,
|
||||
S, LookupSS, true, ObjectType.getTypePtr());
|
||||
|
@ -2514,13 +2524,13 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
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
|
||||
|
@ -2528,7 +2538,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
|
||||
ASTTemplateArgsPtr TemplateArgsPtr(*this,
|
||||
TemplateId->getTemplateArgs(),
|
||||
TemplateId->NumArgs);
|
||||
TemplateId->NumArgs);
|
||||
EndLoc = TemplateId->RAngleLoc;
|
||||
TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
|
||||
TemplateId->TemplateNameLoc,
|
||||
|
@ -2540,7 +2550,7 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
|
||||
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!
|
||||
|
@ -2548,6 +2558,169 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
|||
Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc);
|
||||
return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS,
|
||||
Destructor, DeclPtrTy(), HasTrailingLParen);
|
||||
|
||||
}
|
||||
|
||||
Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
|
||||
SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
const CXXScopeSpec &SS,
|
||||
UnqualifiedId &FirstTypeName,
|
||||
SourceLocation CCLoc,
|
||||
SourceLocation TildeLoc,
|
||||
UnqualifiedId &SecondTypeName,
|
||||
bool HasTrailingLParen) {
|
||||
assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
|
||||
"Invalid first type name in pseudo-destructor");
|
||||
assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
|
||||
"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
|
||||
// left-hand side of the arrow operator shall be of pointer to scalar type.
|
||||
// This scalar type is the object type.
|
||||
QualType ObjectType = BaseE->getType();
|
||||
if (OpKind == tok::arrow) {
|
||||
if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
|
||||
ObjectType = Ptr->getPointeeType();
|
||||
} else {
|
||||
// The user wrote "p->" when she probably meant "p."; fix it.
|
||||
Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
|
||||
<< ObjectType << true
|
||||
<< CodeModificationHint::CreateReplacement(OpLoc, ".");
|
||||
if (isSFINAEContext())
|
||||
return ExprError();
|
||||
|
||||
OpKind = tok::period;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ObjectType->isScalarType()) {
|
||||
Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
|
||||
<< ObjectType << BaseE->getSourceRange();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// 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;
|
||||
TypeSourceInfo *DestructedTypeInfo = 0;
|
||||
if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
|
||||
TypeTy *T = getTypeName(*SecondTypeName.Identifier,
|
||||
SecondTypeName.StartLocation,
|
||||
S, &SS);
|
||||
if (!T) {
|
||||
Diag(SecondTypeName.StartLocation,
|
||||
diag::err_pseudo_dtor_destructor_non_type)
|
||||
<< SecondTypeName.Identifier << ObjectType;
|
||||
if (isSFINAEContext())
|
||||
return ExprError();
|
||||
|
||||
// Recover by assuming we had the right type all along.
|
||||
DestructedType = ObjectType;
|
||||
} else {
|
||||
DestructedType = GetTypeFromParser(T, &DestructedTypeInfo);
|
||||
|
||||
if (!DestructedType->isDependentType() &&
|
||||
!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
|
||||
// The types mismatch. Recover by assuming we had the right type
|
||||
// all along.
|
||||
Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch)
|
||||
<< ObjectType << DestructedType << BaseE->getSourceRange();
|
||||
|
||||
DestructedType = ObjectType;
|
||||
DestructedTypeInfo = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// FIXME: C++0x template aliases would allow a template-id here. For now,
|
||||
// just diagnose this as an error.
|
||||
TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
|
||||
Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template)
|
||||
<< TemplateId->Name << ObjectType
|
||||
<< SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc);
|
||||
if (isSFINAEContext())
|
||||
return ExprError();
|
||||
|
||||
// Recover by assuming we had the right type all along.
|
||||
DestructedType = ObjectType;
|
||||
}
|
||||
|
||||
// C++ [expr.pseudo]p2:
|
||||
// [...] Furthermore, the two type-names in a pseudo-destructor-name of the
|
||||
// form
|
||||
//
|
||||
// ::[opt] nested-name-specifier[opt] type-name :: ~ type-name
|
||||
//
|
||||
// shall designate the same scalar type.
|
||||
QualType ScopeType;
|
||||
if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
|
||||
FirstTypeName.Identifier) {
|
||||
if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
|
||||
TypeTy *T = getTypeName(*FirstTypeName.Identifier,
|
||||
FirstTypeName.StartLocation,
|
||||
S, &SS);
|
||||
if (!T) {
|
||||
Diag(FirstTypeName.StartLocation,
|
||||
diag::err_pseudo_dtor_destructor_non_type)
|
||||
<< FirstTypeName.Identifier << ObjectType;
|
||||
if (isSFINAEContext())
|
||||
return ExprError();
|
||||
} else {
|
||||
// FIXME: Drops source-location information.
|
||||
ScopeType = GetTypeFromParser(T);
|
||||
|
||||
if (!ScopeType->isDependentType() &&
|
||||
!Context.hasSameUnqualifiedType(DestructedType, ScopeType)) {
|
||||
// The types mismatch. Recover by assuming we don't have a scoping
|
||||
// type.
|
||||
Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch)
|
||||
<< ObjectType << ScopeType << BaseE->getSourceRange();
|
||||
|
||||
ScopeType = QualType();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// FIXME: C++0x template aliases would allow a template-id here. For now,
|
||||
// just diagnose this as an error.
|
||||
TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
|
||||
Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template)
|
||||
<< TemplateId->Name << ObjectType
|
||||
<< SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc);
|
||||
if (isSFINAEContext())
|
||||
return ExprError();
|
||||
|
||||
// Recover by assuming we have no scoping type.
|
||||
DestructedType = ObjectType;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Drops the scope type.
|
||||
OwningExprResult Result
|
||||
= Owned(new (Context) CXXPseudoDestructorExpr(Context,
|
||||
Base.takeAs<Expr>(),
|
||||
OpKind == tok::arrow,
|
||||
OpLoc,
|
||||
(NestedNameSpecifier *) SS.getScopeRep(),
|
||||
SS.getRange(),
|
||||
DestructedType,
|
||||
SecondTypeName.StartLocation));
|
||||
if (HasTrailingLParen)
|
||||
return move(Result);
|
||||
|
||||
return DiagnoseDtorReference(SecondTypeName.StartLocation, move(Result));
|
||||
}
|
||||
|
||||
CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp,
|
||||
|
|
|
@ -11,6 +11,7 @@ void g();
|
|||
|
||||
namespace N {
|
||||
typedef Foo Wibble;
|
||||
typedef int OtherInteger;
|
||||
}
|
||||
|
||||
void f(A* a, Foo *f, int *i, double *d) {
|
||||
|
@ -35,8 +36,11 @@ void f(A* a, Foo *f, int *i, double *d) {
|
|||
|
||||
i->~Integer();
|
||||
i->Integer::~Integer();
|
||||
|
||||
i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('double') in pseudo-destructor expression}}
|
||||
i->N::~OtherInteger();
|
||||
i->N::OtherInteger::~OtherInteger();
|
||||
i->N::OtherInteger::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
|
||||
i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
|
||||
i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}}
|
||||
}
|
||||
|
||||
typedef int Integer;
|
||||
|
|
Loading…
Reference in New Issue