[cfe-commits] r146738 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Parse/ParseExprCXX.cpp lib/Sema/SemaExprCXX.cpp test/CXX/special/class.dtor/p10-0x.cpp test/SemaCXX/pseudo-destructors.cpp

David Blaikie dblaikie at gmail.com
Fri Dec 16 08:03:09 PST 2011


Author: dblaikie
Date: Fri Dec 16 10:03:09 2011
New Revision: 146738

URL: http://llvm.org/viewvc/llvm-project?rev=146738&view=rev
Log:
Support decltype in pseudo destructors and dependent destructor calls.

Reviewed by Eli Friedman.

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp
    cfe/trunk/test/SemaCXX/pseudo-destructors.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=146738&r1=146737&r2=146738&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Dec 16 10:03:09 2011
@@ -3250,6 +3250,13 @@
                                        UnqualifiedId &SecondTypeName,
                                        bool HasTrailingLParen);
 
+  ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
+                                       SourceLocation OpLoc,
+                                       tok::TokenKind OpKind,
+                                       SourceLocation TildeLoc, 
+                                       const DeclSpec& DS,
+                                       bool HasTrailingLParen);
+
   /// MaybeCreateExprWithCleanups - If the current full-expression
   /// requires any cleanups, surround it with a ExprWithCleanups node.
   /// Otherwise, just returns the passed-in expression.

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=146738&r1=146737&r2=146738&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Dec 16 10:03:09 2011
@@ -1019,6 +1019,17 @@
   // Parse the tilde.
   assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
   SourceLocation TildeLoc = ConsumeToken();
+
+  if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid() && SS.isEmpty()) {
+    DeclSpec DS(AttrFactory);
+    SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
+    if (DS.getTypeSpecType() == TST_error)
+      return ExprError();
+    return Actions.ActOnPseudoDestructorExpr(getCurScope(), Base, OpLoc, 
+                                             OpKind, TildeLoc, DS, 
+                                             Tok.is(tok::l_paren));
+  }
+
   if (!Tok.is(tok::identifier)) {
     Diag(Tok, diag::err_destructor_tilde_identifier);
     return ExprError();

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=146738&r1=146737&r2=146738&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Dec 16 10:03:09 2011
@@ -28,6 +28,7 @@
 #include "clang/Basic/PartialDiagnostic.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
+#include "TypeLocBuilder.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/ErrorHandling.h"
 using namespace clang;
@@ -4313,37 +4314,45 @@
                        /*RPLoc*/ ExpectedLParenLoc);
 }
 
-ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
-                                           SourceLocation OpLoc,
-                                           tok::TokenKind OpKind,
-                                           const CXXScopeSpec &SS,
-                                           TypeSourceInfo *ScopeTypeInfo,
-                                           SourceLocation CCLoc,
-                                           SourceLocation TildeLoc,
-                                         PseudoDestructorTypeStorage Destructed,
-                                           bool HasTrailingLParen) {
-  TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
-
+static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *Base, 
+                   tok::TokenKind& OpKind, SourceLocation OpLoc) {
   // 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 = Base->getType();
   if (OpKind == tok::arrow) {
     if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
       ObjectType = Ptr->getPointeeType();
     } else if (!Base->isTypeDependent()) {
       // The user wrote "p->" when she probably meant "p."; fix it.
-      Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+      S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
         << ObjectType << true
         << FixItHint::CreateReplacement(OpLoc, ".");
-      if (isSFINAEContext())
-        return ExprError();
+      if (S.isSFINAEContext())
+        return true;
 
       OpKind = tok::period;
     }
   }
 
+  return false;
+}
+
+ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
+                                           SourceLocation OpLoc,
+                                           tok::TokenKind OpKind,
+                                           const CXXScopeSpec &SS,
+                                           TypeSourceInfo *ScopeTypeInfo,
+                                           SourceLocation CCLoc,
+                                           SourceLocation TildeLoc,
+                                         PseudoDestructorTypeStorage Destructed,
+                                           bool HasTrailingLParen) {
+  TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
+
+  QualType ObjectType = Base->getType();
+  if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+    return ExprError();
+
   if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) {
     Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
       << ObjectType << Base->getSourceRange();
@@ -4442,25 +4451,9 @@
           SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
          "Invalid second type name in pseudo-destructor");
 
-  // 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 = Base->getType();
-  if (OpKind == tok::arrow) {
-    if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
-      ObjectType = Ptr->getPointeeType();
-    } 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
-        << FixItHint::CreateReplacement(OpLoc, ".");
-      if (isSFINAEContext())
-        return ExprError();
-
-      OpKind = tok::period;
-    }
-  }
+  if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+    return ExprError();
 
   // Compute the object type that we should use for name lookup purposes. Only
   // record types and dependent types matter.
@@ -4580,6 +4573,30 @@
                                    Destructed, HasTrailingLParen);
 }
 
+ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
+                                           SourceLocation OpLoc,
+                                           tok::TokenKind OpKind,
+                                           SourceLocation TildeLoc, 
+                                           const DeclSpec& DS,
+                                           bool HasTrailingLParen) {
+  
+  QualType ObjectType = Base->getType();
+  if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc))
+    return ExprError();
+
+  QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+
+  TypeLocBuilder TLB;
+  DecltypeTypeLoc DecltypeTL = TLB.push<DecltypeTypeLoc>(T);
+  DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc());
+  TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T);
+  PseudoDestructorTypeStorage Destructed(DestructedTypeInfo);
+
+  return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(),
+                                   0, SourceLocation(), TildeLoc,
+                                   Destructed, HasTrailingLParen);
+}
+
 ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
                                         CXXMethodDecl *Method,
                                         bool HadMultipleCandidates) {

Modified: cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp?rev=146738&r1=146737&r2=146738&view=diff
==============================================================================
--- cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp (original)
+++ cfe/trunk/test/CXX/special/class.dtor/p10-0x.cpp Fri Dec 16 10:03:09 2011
@@ -5,16 +5,18 @@
 struct B {};
 template<typename T>
 void b(const T *x, const A *y) {
-  // FIXME: this parses as a pseudo destructor call which doesn't have decltype support yet
-  x->~decltype(T())(); // expected-error{{expected a class name after '~' to name a destructor}}
+  x->~decltype(T())();
+  x->~decltype(*x)(); // expected-error{{the type of object expression ('const int') does not match the type being destroyed ('decltype(*x)' (aka 'const int &')) in pseudo-destructor expression}} \
+                         expected-error{{no member named '~const struct A &' in 'A'}}
+  x->~decltype(int())(); // expected-error{{no member named '~int' in 'A'}}
 
   y->~decltype(*y)(); // expected-error{{destructor type 'decltype(*y)' (aka 'const A &') in object destruction expression does not match the type 'const A' of the object being destroyed}}
   y->~decltype(T())(); // expected-error{{destructor type 'decltype(T())' in object destruction expression does not match the type 'const A' of the object being destroyed}}
   y->~decltype(A())();
 }
-template void b(const int*, const A*);
-template void b(const A*,const A*);
-void a(const A *x) {
+template void b(const int*, const A*); // expected-note{{in instantiation of function template specialization 'b<int>' requested here}}
+template void b(const A*,const A*); // expected-note{{in instantiation of function template specialization 'b<A>' requested here}}
+void a(const A *x, int i, int *pi) {
   x->~decltype(A())();
   x->~decltype(*x)(); // expected-error{{destructor type 'decltype(*x)' (aka 'const A &') in object destruction expression does not match the type 'const A' of the object being destroyed}}
   x->~decltype()(); // expected-error{{expected expression}}
@@ -23,4 +25,15 @@
   // this last one could be better, mentioning that the nested-name-specifier could be removed or a type name after the ~
   x->::A::~decltype(*x)(); // expected-error{{expected a class name after '~' to name a destructor}}
   y->~decltype(A())(); // expected-error{{use of undeclared identifier 'y'}}
+
+  typedef int *intp;
+  i->~decltype(int())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+  i.~decltype(int())();
+  i->~decltype(intp())(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}} \
+                             expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
+  i.~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
+  pi->~decltype(int())();
+  pi.~decltype(int())(); // expected-error{{the type of object expression ('int *') does not match the type being destroyed ('decltype(int())' (aka 'int')) in pseudo-destructor expression}}
+  pi.~decltype(intp())();
+  pi->~decltype(intp())(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('decltype(intp())' (aka 'int *')) in pseudo-destructor expression}}
 }

Modified: cfe/trunk/test/SemaCXX/pseudo-destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pseudo-destructors.cpp?rev=146738&r1=146737&r2=146738&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/pseudo-destructors.cpp (original)
+++ cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Fri Dec 16 10:03:09 2011
@@ -19,7 +19,7 @@
   cvt->T::~T(); // no-warning
 }
 
-void f(A* a, Foo *f, int *i, double *d) {
+void f(A* a, Foo *f, int *i, double *d, int ii) {
   a->~A();
   a->A::~A();
   
@@ -46,6 +46,9 @@
   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}}
 
+  ii->~Integer(); // expected-error{{member reference type 'int' is not a pointer; maybe you meant to use '.'?}}
+  ii.~Integer();
+
   cv_test(a);
   cv_test(f);
   cv_test(i);





More information about the cfe-commits mailing list