]> granicus.if.org Git - clang/commitdiff
Implement C++ [basic.lookup.classref]p3, which states how the type
authorDouglas Gregor <dgregor@apple.com>
Fri, 20 Nov 2009 22:03:38 +0000 (22:03 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 20 Nov 2009 22:03:38 +0000 (22:03 +0000)
name 'T' is looked up in the expression

  t.~T()

Previously, we weren't looking into the type of "t", and therefore
would fail when T actually referred to an injected-class-name. Fixes
PR5530.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89493 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Action.h
lib/Parse/MinimalAction.cpp
lib/Parse/ParseExprCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
test/SemaCXX/pseudo-destructors.cpp

index 45891bc0c9807e8c39f05309e766fac0fc325704..018cc1454038ea5030184a16036909a1c4566ba8 100644 (file)
@@ -203,11 +203,15 @@ public:
   /// this occurs when deriving from "std::vector<T>::allocator_type", where T
   /// is a template parameter.
   ///
+  /// \param ObjectType if we're checking whether an identifier is a type
+  /// within a C++ member access expression, this will be the type of the 
+  /// 
   /// \returns the type referred to by this identifier, or NULL if the type
   /// does not name an identifier.
   virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
                               Scope *S, const CXXScopeSpec *SS = 0,
-                              bool isClassName = false) = 0;
+                              bool isClassName = false,
+                              TypeTy *ObjectType = 0) = 0;
 
   /// isTagName() - This method is called *for error recovery purposes only*
   /// to determine if the specified name is a valid tag name ("struct foo").  If
@@ -2518,7 +2522,8 @@ public:
   /// does not name an identifier.
   virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
                               Scope *S, const CXXScopeSpec *SS,
-                              bool isClassName = false);
+                              bool isClassName = false,
+                              TypeTy *ObjectType = 0);
 
   /// isCurrentClassName - Always returns false, because MinimalAction
   /// does not support C++ classes with constructors.
index 7681eac6ed8a4d0eb6b6a2022b801851f649c2c8..aa0b89b1a3a23f42212b5a26840ea8298e93f791 100644 (file)
@@ -144,7 +144,7 @@ void MinimalAction::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
 Action::TypeTy *
 MinimalAction::getTypeName(IdentifierInfo &II, SourceLocation Loc,
                            Scope *S, const CXXScopeSpec *SS,
-                           bool isClassName) {
+                           bool isClassName, TypeTy *ObjectType) {
   if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
     if (TI->isTypeName)
       return TI;
index b2ecc9e827f1db8c9cebfc5b4bd6ebda7450ebbc..145c8616eb855620b55197efa721d47c47cd5431 100644 (file)
@@ -1010,7 +1010,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
   
   // Parse the type-specifier-seq.
   DeclSpec DS;
-  if (ParseCXXTypeSpecifierSeq(DS))
+  if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType?
     return true;
   
   // Parse the conversion-declarator, which is merely a sequence of
@@ -1152,7 +1152,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
     
     // Note that this is a destructor name.
     Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc,
-                                             CurScope, &SS);
+                                             CurScope, &SS, false, ObjectType);
     if (!Ty) {
       if (ObjectType)
         Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
index 72039e275690cb8c4c7c051bab884eb45ccb43a9..6e74f9277a1a7ffa77debc9bcb694b8947b26d9a 100644 (file)
@@ -533,7 +533,8 @@ public:
 
   virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
                               Scope *S, const CXXScopeSpec *SS,
-                              bool isClassName = false);
+                              bool isClassName = false,
+                              TypeTy *ObjectType = 0);
   virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
   virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II, 
                                        SourceLocation IILoc,
index b5109f825e57f34e6a84d3cb0dea887a108e0278..27c491c88202e4aab7ddee2b77490bfcaf3ac9fe 100644 (file)
@@ -66,31 +66,68 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(DeclPtrTy Ptr) {
 /// and then return NULL.
 Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
                                 Scope *S, const CXXScopeSpec *SS,
-                                bool isClassName) {
-  // C++ [temp.res]p3:
-  //   A qualified-id that refers to a type and in which the
-  //   nested-name-specifier depends on a template-parameter (14.6.2)
-  //   shall be prefixed by the keyword typename to indicate that the
-  //   qualified-id denotes a type, forming an
-  //   elaborated-type-specifier (7.1.5.3).
-  //
-  // We therefore do not perform any name lookup if the result would
-  // refer to a member of an unknown specialization.
-  if (SS && isUnknownSpecialization(*SS)) {
-    if (!isClassName)
+                                bool isClassName,
+                                TypeTy *ObjectTypePtr) {
+  // Determine where we will perform name lookup.
+  DeclContext *LookupCtx = 0;
+  if (ObjectTypePtr) {
+    QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
+    if (ObjectType->isRecordType())
+      LookupCtx = computeDeclContext(ObjectType);
+  } else if (SS && SS->isSet()) {
+    LookupCtx = computeDeclContext(*SS, false);
+
+    if (!LookupCtx) {
+      if (isDependentScopeSpecifier(*SS)) {
+        // C++ [temp.res]p3:
+        //   A qualified-id that refers to a type and in which the
+        //   nested-name-specifier depends on a template-parameter (14.6.2)
+        //   shall be prefixed by the keyword typename to indicate that the
+        //   qualified-id denotes a type, forming an
+        //   elaborated-type-specifier (7.1.5.3).
+        //
+        // We therefore do not perform any name lookup if the result would
+        // refer to a member of an unknown specialization.
+        if (!isClassName)
+          return 0;
+        
+        // We know from the grammar that this name refers to a type, so build a
+        // TypenameType node to describe the type.
+        // FIXME: Record somewhere that this TypenameType node has no "typename"
+        // keyword associated with it.
+        return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
+                                 II, SS->getRange()).getAsOpaquePtr();
+      }
+      
+      return 0;
+    }
+    
+    if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS))
       return 0;
-
-    // We know from the grammar that this name refers to a type, so build a
-    // TypenameType node to describe the type.
-    // FIXME: Record somewhere that this TypenameType node has no "typename"
-    // keyword associated with it.
-    return CheckTypenameType((NestedNameSpecifier *)SS->getScopeRep(),
-                             II, SS->getRange()).getAsOpaquePtr();
   }
-
+      
   LookupResult Result(*this, &II, NameLoc, LookupOrdinaryName);
-  LookupParsedName(Result, S, SS, false);
-
+  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.
+    LookupQualifiedName(Result, LookupCtx);
+
+    if (ObjectTypePtr && Result.empty()) {
+      // C++ [basic.lookup.classref]p3:
+      //   If the unqualified-id is ~type-name, the type-name is looked up
+      //   in the context of the entire postfix-expression. If the type T of 
+      //   the object expression is of a class type C, the type-name is also
+      //   looked up in the scope of class C. At least one of the lookups shall
+      //   find a name that refers to (possibly cv-qualified) T.
+      LookupName(Result, S);
+    }
+  } else {
+    // Perform unqualified name lookup.
+    LookupName(Result, S);
+  }
+  
   NamedDecl *IIDecl = 0;
   switch (Result.getResultKind()) {
   case LookupResult::NotFound:
index 0850c44a36f9dc68f9fd31028400fd59e0b1ce83..8f69def9fd4f1d752665532c34a4510b106b1798 100644 (file)
@@ -38,3 +38,12 @@ typedef int Integer;
 void destroy_without_call(int *ip) {
   ip->~Integer; // expected-error{{called immediately}}
 }
+
+// PR5530
+namespace N1 {
+  class X0 { };
+}
+
+void test_X0(N1::X0 &x0) {
+  x0.~X0();
+}