[cfe-commits] r81009 - in /cfe/trunk: include/clang/AST/ExprCXX.h include/clang/AST/StmtNodes.def include/clang/Basic/DiagnosticSemaKinds.td lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprScalar.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/TreeTransform.h test/SemaCXX/pseudo-destructors.cpp test/SemaTemplate/member-access-expr.cpp
Douglas Gregor
dgregor at apple.com
Fri Sep 4 10:36:40 PDT 2009
Author: dgregor
Date: Fri Sep 4 12:36:40 2009
New Revision: 81009
URL: http://llvm.org/viewvc/llvm-project?rev=81009&view=rev
Log:
Implement AST, semantics, and CodeGen for C++ pseudo-destructor
expressions, e.g.,
p->~T()
when p is a pointer to a scalar type.
We don't currently diagnose errors when pseudo-destructor expressions
are used in any way other than by forming a call.
Modified:
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/include/clang/AST/StmtNodes.def
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/AST/StmtPrinter.cpp
cfe/trunk/lib/AST/StmtProfile.cpp
cfe/trunk/lib/CodeGen/CGExpr.cpp
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/SemaCXX/pseudo-destructors.cpp
cfe/trunk/test/SemaTemplate/member-access-expr.cpp
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Sep 4 12:36:40 2009
@@ -851,6 +851,108 @@
virtual child_iterator child_end();
};
+/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]).
+///
+/// Example:
+///
+/// \code
+/// template<typename T>
+/// void destroy(T* ptr) {
+/// ptr->~T();
+/// }
+/// \endcode
+///
+/// When the template is parsed, the expression \c ptr->~T will be stored as
+/// a member reference expression. If it then instantiated with a scalar type
+/// as a template argument for T, the resulting expression will be a
+/// pseudo-destructor expression.
+class CXXPseudoDestructorExpr : public Expr {
+ /// \brief The base expression (that is being destroyed).
+ Stmt *Base;
+
+ /// \brief Whether the operator was an arrow ('->'); otherwise, it was a
+ /// period ('.').
+ bool IsArrow : 1;
+
+ /// \brief The location of the '.' or '->' operator.
+ SourceLocation OperatorLoc;
+
+ /// \brief The nested-name-specifier that follows the operator, if present.
+ NestedNameSpecifier *Qualifier;
+
+ /// \brief The source range that covers the nested-name-specifier, if
+ /// present.
+ SourceRange QualifierRange;
+
+ /// \brief The type being destroyed.
+ QualType DestroyedType;
+
+ /// \brief The location of the type after the '~'.
+ SourceLocation DestroyedTypeLoc;
+
+public:
+ CXXPseudoDestructorExpr(ASTContext &Context,
+ Expr *Base, bool isArrow, SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ QualType DestroyedType,
+ SourceLocation DestroyedTypeLoc)
+ : Expr(CXXPseudoDestructorExprClass,
+ Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
+ false, 0)),
+ /*isTypeDependent=*/false,
+ /*isValueDependent=*/Base->isValueDependent()),
+ Base(static_cast<Stmt *>(Base)), IsArrow(isArrow),
+ OperatorLoc(OperatorLoc), Qualifier(Qualifier),
+ QualifierRange(QualifierRange), DestroyedType(DestroyedType),
+ DestroyedTypeLoc(DestroyedTypeLoc) { }
+
+ void setBase(Expr *E) { Base = E; }
+ Expr *getBase() const { return cast<Expr>(Base); }
+
+ /// \brief Determines whether this member expression actually had
+ /// a C++ nested-name-specifier prior to the name of the member, e.g.,
+ /// x->Base::foo.
+ bool hasQualifier() const { return Qualifier != 0; }
+
+ /// \brief If the member name was qualified, retrieves the source range of
+ /// the nested-name-specifier that precedes the member name. Otherwise,
+ /// returns an empty source range.
+ SourceRange getQualifierRange() const { return QualifierRange; }
+
+ /// \brief If the member name was qualified, retrieves the
+ /// nested-name-specifier that precedes the member name. Otherwise, returns
+ /// NULL.
+ NestedNameSpecifier *getQualifier() const { return Qualifier; }
+
+ /// \brief Determine whether this pseudo-destructor expression was written
+ /// using an '->' (otherwise, it used a '.').
+ bool isArrow() const { return IsArrow; }
+ void setArrow(bool A) { IsArrow = A; }
+
+ /// \brief Retrieve the location of the '.' or '->' operator.
+ SourceLocation getOperatorLoc() const { return OperatorLoc; }
+
+ /// \brief Retrieve the type that is being destroyed.
+ QualType getDestroyedType() const { return DestroyedType; }
+
+ /// \brief Retrieve the location of the type being destroyed.
+ SourceLocation getDestroyedTypeLoc() const { return DestroyedTypeLoc; }
+
+ virtual SourceRange getSourceRange() const {
+ return SourceRange(Base->getLocStart(), DestroyedTypeLoc);
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXPseudoDestructorExprClass;
+ }
+ static bool classof(const CXXPseudoDestructorExpr *) { return true; }
+
+ // Iterators
+ virtual child_iterator child_begin();
+ virtual child_iterator child_end();
+};
+
/// \brief Represents the name of a function that has not been
/// resolved to any declaration.
///
Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Fri Sep 4 12:36:40 2009
@@ -124,6 +124,7 @@
EXPR(CXXConditionDeclExpr , DeclRefExpr)
EXPR(CXXNewExpr , Expr)
EXPR(CXXDeleteExpr , Expr)
+EXPR(CXXPseudoDestructorExpr, Expr)
EXPR(UnresolvedFunctionNameExpr , Expr)
EXPR(UnaryTypeTraitExpr , Expr)
EXPR(QualifiedDeclRefExpr , DeclRefExpr)
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 4 12:36:40 2009
@@ -1588,9 +1588,15 @@
def err_ident_in_pseudo_dtor_not_a_type : Error<
"identifier %0 in pseudo-destructor expression does not name a type">;
-def err_type_in_pseudo_dtor_not_a_class_type : Error<
- "type %0 in pseudo-destructor expression is not a class type">;
-
+def err_pseudo_dtor_base_not_scalar : Error<
+ "object expression of non-scalar type %0 cannot be used in a "
+ "pseudo-destructor expression">;
+def err_pseudo_dtor_type_mismatch : Error<
+ "the type of object expression (%0) does not match the type being destroyed "
+ "(%1) in pseudo-destructor expression">;
+def err_pseudo_dtor_call_with_args : Error<
+ "call to pseudo-destructor cannot have any arguments">;
+
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/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Fri Sep 4 12:36:40 2009
@@ -116,6 +116,12 @@
Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; }
Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; }
+// CXXPseudoDestructorExpr
+Stmt::child_iterator CXXPseudoDestructorExpr::child_begin() { return &Base; }
+Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
+ return &Base + 1;
+}
+
// UnresolvedFunctionNameExpr
Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() {
return child_iterator();
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Fri Sep 4 12:36:40 2009
@@ -1107,6 +1107,20 @@
PrintExpr(E->getArgument());
}
+void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
+ PrintExpr(E->getBase());
+ if (E->isArrow())
+ OS << "->";
+ else
+ OS << '.';
+ if (E->getQualifier())
+ E->getQualifier()->print(OS, Policy);
+
+ std::string TypeS;
+ E->getDestroyedType().getAsStringInternal(TypeS, Policy);
+ OS << TypeS;
+}
+
void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) {
OS << E->getName().getAsString();
}
Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Fri Sep 4 12:36:40 2009
@@ -502,6 +502,13 @@
ID.AddInteger(S->getNumConstructorArgs());
}
+void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ VisitNestedNameSpecifier(S->getQualifier());
+ VisitType(S->getDestroyedType());
+}
+
void
StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) {
VisitExpr(S);
Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Fri Sep 4 12:36:40 2009
@@ -1234,6 +1234,16 @@
if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(TargetDecl))
return EmitCXXOperatorMemberCallExpr(CE, MD);
+ if (isa<CXXPseudoDestructorExpr>(E->getCallee())) {
+ // C++ [expr.pseudo]p1:
+ // The result shall only be used as the operand for the function call
+ // operator (), and the result of such a call has type void. The only
+ // effect is the evaluation of the postfix-expression before the dot or
+ // arrow.
+ EmitScalarExpr(E->getCallee());
+ return RValue::get(0);
+ }
+
llvm::Value *Callee = EmitScalarExpr(E->getCallee());
return EmitCall(Callee, E->getCallee()->getType(),
E->arg_begin(), E->arg_end(), TargetDecl);
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Fri Sep 4 12:36:40 2009
@@ -305,7 +305,17 @@
CGF.EmitCXXDeleteExpr(E);
return 0;
}
-
+
+ Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) {
+ // C++ [expr.pseudo]p1:
+ // The result shall only be used as the operand for the function call
+ // operator (), and the result of such a call has type void. The only
+ // effect is the evaluation of the postfix-expression before the dot or
+ // arrow.
+ CGF.EmitScalarExpr(E->getBase());
+ return 0;
+ }
+
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
if (CGF.getContext().getLangOptions().OverflowChecking
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Sep 4 12:36:40 2009
@@ -1998,7 +1998,7 @@
Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
Expr *BaseExpr = Base.takeAs<Expr>();
- assert(BaseExpr && "no record expression");
+ assert(BaseExpr && "no base expression");
// Perform default conversions.
DefaultFunctionArrayConversion(BaseExpr);
@@ -2230,6 +2230,47 @@
<< MemberName << int(OpKind == tok::arrow));
}
+ // Handle pseudo-destructors (C++ [expr.pseudo]). Since anything referring
+ // into a record type was handled above, any destructor we see here is a
+ // pseudo-destructor.
+ if (MemberName.getNameKind() == DeclarationName::CXXDestructorName) {
+ // 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.
+ if (!BaseType->isScalarType())
+ return Owned(Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+ << BaseType << BaseExpr->getSourceRange());
+
+ // [...] The type designated by the pseudo-destructor-name shall be the
+ // same as the object type.
+ if (!MemberName.getCXXNameType()->isDependentType() &&
+ !Context.hasSameUnqualifiedType(BaseType, MemberName.getCXXNameType()))
+ return Owned(Diag(OpLoc, diag::err_pseudo_dtor_type_mismatch)
+ << BaseType << MemberName.getCXXNameType()
+ << BaseExpr->getSourceRange() << SourceRange(MemberLoc));
+
+ // [...] 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.
+ //
+ // FIXME: DPG can't see any way to trigger this particular clause, so it
+ // isn't checked here.
+
+ // FIXME: We've lost the precise spelling of the type by going through
+ // DeclarationName. Can we do better?
+ return Owned(new (Context) CXXPseudoDestructorExpr(Context, BaseExpr,
+ OpKind == tok::arrow,
+ OpLoc,
+ (NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
+ SS? SS->getRange() : SourceRange(),
+ MemberName.getCXXNameType(),
+ MemberLoc));
+ }
+
// Handle properties on ObjC 'Class' types.
if (OpKind == tok::period && BaseType->isObjCClassType()) {
// Also must look for a getter name which uses property syntax.
@@ -2684,6 +2725,25 @@
DeclarationName UnqualifiedName;
if (getLangOptions().CPlusPlus) {
+ // If this is a pseudo-destructor expression, build the call immediately.
+ if (isa<CXXPseudoDestructorExpr>(Fn)) {
+ if (NumArgs > 0) {
+ // Pseudo-destructor calls should not have any arguments.
+ Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args)
+ << CodeModificationHint::CreateRemoval(
+ SourceRange(Args[0]->getLocStart(),
+ Args[NumArgs-1]->getLocEnd()));
+
+ for (unsigned I = 0; I != NumArgs; ++I)
+ Args[I]->Destroy(Context);
+
+ NumArgs = 0;
+ }
+
+ return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy,
+ RParenLoc));
+ }
+
// Determine whether this is a dependent call inside a C++ template,
// in which case we won't do any semantic analysis now.
// FIXME: Will need to cache the results of name lookup (including ADL) in
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Sep 4 12:36:40 2009
@@ -1821,26 +1821,19 @@
if (SS && SS->isInvalid())
return ExprError();
- Expr *BaseExpr = (Expr *)Base.get();
+ QualType BaseType;
+ if (SS && isUnknownSpecialization(*SS))
+ BaseType = Context.getTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
+ ClassName);
+ else {
+ TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, SS);
+ if (!BaseTy) {
+ Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+ << ClassName;
+ return ExprError();
+ }
- if (BaseExpr->isTypeDependent() ||
- (SS && isDependentScopeSpecifier(*SS))) {
- // FIXME: Return an unresolved ref expr.
- return ExprError();
- }
-
- TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, SS);
- if (!BaseTy) {
- Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
- << ClassName;
- return ExprError();
- }
-
- QualType BaseType = GetTypeFromParser(BaseTy);
- if (!BaseType->isRecordType()) {
- Diag(ClassNameLoc, diag::err_type_in_pseudo_dtor_not_a_class_type)
- << BaseType;
- return ExprError();
+ BaseType = GetTypeFromParser(BaseTy);
}
CanQualType CanBaseType = Context.getCanonicalType(BaseType);
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Sep 4 12:36:40 2009
@@ -783,6 +783,36 @@
return getSema().ActOnParenExpr(LParen, RParen, move(SubExpr));
}
+ /// \brief Build a new pseudo-destructor expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base,
+ SourceLocation OperatorLoc,
+ bool isArrow,
+ SourceLocation DestroyedTypeLoc,
+ QualType DestroyedType,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange) {
+ CXXScopeSpec SS;
+ if (Qualifier) {
+ SS.setRange(QualifierRange);
+ SS.setScopeRep(Qualifier);
+ }
+
+ DeclarationName Name
+ = SemaRef.Context.DeclarationNames.getCXXDestructorName(
+ SemaRef.Context.getCanonicalType(DestroyedType));
+
+ return getSema().BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
+ OperatorLoc,
+ isArrow? tok::arrow : tok::period,
+ DestroyedTypeLoc,
+ Name,
+ Sema::DeclPtrTy::make((Decl *)0),
+ &SS);
+ }
+
/// \brief Build a new unary operator expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -3814,6 +3844,43 @@
template<typename Derived>
Sema::OwningExprResult
+TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
+ CXXPseudoDestructorExpr *E) {
+ OwningExprResult Base = getDerived().TransformExpr(E->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ NestedNameSpecifier *Qualifier
+ = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
+ E->getQualifierRange());
+ if (E->getQualifier() && !Qualifier)
+ return SemaRef.ExprError();
+
+ QualType DestroyedType;
+ {
+ TemporaryBase Rebase(*this, E->getDestroyedTypeLoc(), DeclarationName());
+ DestroyedType = getDerived().TransformType(E->getDestroyedType());
+ if (DestroyedType.isNull())
+ return SemaRef.ExprError();
+ }
+
+ if (!getDerived().AlwaysRebuild() &&
+ Base.get() == E->getBase() &&
+ Qualifier == E->getQualifier() &&
+ DestroyedType == E->getDestroyedType())
+ return SemaRef.Owned(E->Retain());
+
+ return getDerived().RebuildCXXPseudoDestructorExpr(move(Base),
+ E->getOperatorLoc(),
+ E->isArrow(),
+ E->getDestroyedTypeLoc(),
+ DestroyedType,
+ Qualifier,
+ E->getQualifierRange());
+}
+
+template<typename Derived>
+Sema::OwningExprResult
TreeTransform<Derived>::TransformUnresolvedFunctionNameExpr(
UnresolvedFunctionNameExpr *E) {
// There is no transformation we can apply to an unresolved function name.
Modified: cfe/trunk/test/SemaCXX/pseudo-destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pseudo-destructors.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/pseudo-destructors.cpp (original)
+++ cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Fri Sep 4 12:36:40 2009
@@ -4,10 +4,31 @@
enum Foo { F };
typedef Foo Bar;
-void f(A* a) {
+typedef int Integer;
+
+void g();
+
+namespace N {
+ typedef Foo Wibble;
+}
+
+void f(A* a, Foo *f, int *i) {
a->~A();
a->A::~A();
a->~foo(); // expected-error{{identifier 'foo' in pseudo-destructor expression does not name a type}}
- a->~Bar(); // expected-error{{type 'Bar' (aka 'enum Foo') in pseudo-destructor expression is not a class type}}
+
+ // FIXME: the type printed below isn't wonderful
+ a->~Bar(); // expected-error{{no member named}}
+
+ f->~Bar();
+ f->~Foo();
+ i->~Bar(); // expected-error{{does not match}}
+
+ g().~Bar(); // expected-error{{non-scalar}}
+
+ f->::~Bar();
+ f->N::~Wibble();
+
+ f->::~Bar(17, 42); // expected-error{{cannot have any arguments}}
}
Modified: cfe/trunk/test/SemaTemplate/member-access-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/member-access-expr.cpp?rev=81009&r1=81008&r2=81009&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/member-access-expr.cpp (original)
+++ cfe/trunk/test/SemaTemplate/member-access-expr.cpp Fri Sep 4 12:36:40 2009
@@ -59,3 +59,19 @@
convert<int>(x2);
convert<long>(x2); // expected-note{{instantiation}}
}
+
+template<typename T>
+void destruct(T* ptr) {
+ ptr->~T();
+}
+
+template<typename T>
+void destruct_intptr(int *ip) {
+ ip->~T();
+}
+
+void test_destruct(X2 *x2p, int *ip) {
+ destruct(x2p);
+ destruct(ip);
+ destruct_intptr<int>(ip);
+}
\ No newline at end of file
More information about the cfe-commits
mailing list