[cfe-commits] r97058 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Action.h lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/pseudo-destructors.cpp
Douglas Gregor
dgregor at apple.com
Wed Feb 24 13:29:12 PST 2010
Author: dgregor
Date: Wed Feb 24 15:29:12 2010
New Revision: 97058
URL: http://llvm.org/viewvc/llvm-project?rev=97058&view=rev
Log:
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).
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/test/SemaCXX/pseudo-destructors.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb 24 15:29:12 2010
@@ -2078,7 +2078,12 @@
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">;
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Feb 24 15:29:12 2010
@@ -327,13 +327,26 @@
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.
///
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 24 15:29:12 2010
@@ -240,7 +240,9 @@
// 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 @@
}
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;
}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 15:29:12 2010
@@ -2178,6 +2178,20 @@
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 @@
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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Feb 24 15:29:12 2010
@@ -332,6 +332,54 @@
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.
///
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 24 15:29:12 2010
@@ -3178,23 +3178,6 @@
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 @@
// call now.
if (!HasTrailingLParen &&
Id.getKind() == UnqualifiedId::IK_DestructorName)
- return DiagnoseDtorReference(*this, NameLoc, move(Result));
+ return DiagnoseDtorReference(NameLoc, move(Result));
return move(Result);
}
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 15:29:12 2010
@@ -2410,31 +2410,41 @@
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 @@
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 @@
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 @@
}
}
}
-
+
// Produce a destructor name based on the second type-name (which
// follows the tilde).
TypeTy *DestructedType;
@@ -2490,7 +2500,7 @@
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 @@
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 @@
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 @@
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 @@
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,
Modified: cfe/trunk/test/SemaCXX/pseudo-destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pseudo-destructors.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/pseudo-destructors.cpp (original)
+++ cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Wed Feb 24 15:29:12 2010
@@ -11,6 +11,7 @@
namespace N {
typedef Foo Wibble;
+ typedef int OtherInteger;
}
void f(A* a, Foo *f, int *i, double *d) {
@@ -35,8 +36,11 @@
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;
More information about the cfe-commits
mailing list