]> granicus.if.org Git - clang/commitdiff
Decltype in non-pseudo (& non-dependent) dtor calls.
authorDavid Blaikie <dblaikie@gmail.com>
Thu, 8 Dec 2011 16:13:53 +0000 (16:13 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Thu, 8 Dec 2011 16:13:53 +0000 (16:13 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146155 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Parse/ParseExprCXX.cpp
lib/Sema/SemaExprCXX.cpp
test/CXX/special/class.dtor/p10-0x.cpp [new file with mode: 0644]

index 89e7662f03df6869e3a7bfc978365e5480acefda..3133f708ee0c7e6252dc395b7e6619088fe48bde 100644 (file)
@@ -3020,6 +3020,8 @@ public:
                                ParsedType ObjectType,
                                bool EnteringContext);
 
+  ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType);
+
   // Checks that reinterpret casts don't have undefined behavior.
   void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType,
                                       bool IsDereference, SourceRange Range);
index 79d2ec21ab09cd8b3a9e224b21cb0dd6bf443464..182f2f080d57c0ca21ee45db8c840eed553b35eb 100644 (file)
@@ -1966,6 +1966,16 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
     
     // Parse the '~'.
     SourceLocation TildeLoc = ConsumeToken();
+
+    if (SS.isEmpty() && Tok.is(tok::kw_decltype)) {
+      DeclSpec DS(AttrFactory);
+      SourceLocation EndLoc = ParseDecltypeSpecifier(DS);
+      if (ParsedType Type = Actions.getDestructorType(DS, ObjectType)) {
+        Result.setDestructorName(TildeLoc, Type, EndLoc);
+        return false;
+      }
+      return true;
+    }
     
     // Parse the class-name.
     if (Tok.isNot(tok::identifier)) {
index 06837fef8471498a19b91a8a2cf8ad4ca2cf1b65..af297840c39c568d50ebb2002adc048345397331 100644 (file)
@@ -265,6 +265,22 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
   return ParsedType();
 }
 
+ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
+    if (DS.getTypeSpecType() == DeclSpec::TST_error)
+      return ParsedType();
+    assert(DS.getTypeSpecType() == DeclSpec::TST_decltype 
+           && "only get destructor types from declspecs");
+    QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
+    QualType SearchType = GetTypeFromParser(ObjectType);
+    if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) {
+      return ParsedType::make(T);
+    }
+      
+    Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch)
+      << T << SearchType;
+    return ParsedType();
+}
+
 /// \brief Build a C++ typeid expression with a type operand.
 ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType,
                                 SourceLocation TypeidLoc,
diff --git a/test/CXX/special/class.dtor/p10-0x.cpp b/test/CXX/special/class.dtor/p10-0x.cpp
new file mode 100644 (file)
index 0000000..121624e
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// PR10127/N3031
+struct A { ~A(); };
+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}}
+
+  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) {
+  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}}
+  x->~decltype(B())(); // expected-error{{destructor type 'decltype(B())' (aka 'B') in object destruction expression does not match the type 'const A' of the object being destroyed}}
+  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}}
+  // 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}}
+}