[cfe-commits] r66662 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaLookup.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaCXX/nested-name-spec.cpp test/SemaTemplate/instantiate-typedef.cpp

Douglas Gregor dgregor at apple.com
Wed Mar 11 09:48:54 PDT 2009


Author: dgregor
Date: Wed Mar 11 11:48:53 2009
New Revision: 66662

URL: http://llvm.org/viewvc/llvm-project?rev=66662&view=rev
Log:
Add basic, hackish support for instantiation of typedefs in a class
template. More importantly, start to sort out the issues regarding
complete types and nested-name-specifiers, especially the question of:
when do we instantiate a class template specialization that occurs to
the left of a '::' in a nested-name-specifier?



Added:
    cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/SemaCXX/nested-name-spec.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Wed Mar 11 11:48:53 2009
@@ -231,6 +231,10 @@
 DIAG(warn_objc_property_attr_mutually_exclusive, WARNING,
      "property attributes '%0' and '%1' are mutually exclusive")
 
+// C++ name lookup
+DIAG(err_incomplete_nested_name_spec, ERROR,
+     "incomplete type %0 named in nested name specifier")
+
 // C++ class members
 DIAG(err_storageclass_invalid_for_member, ERROR,
      "storage class specified for a member declaration")

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Mar 11 11:48:53 2009
@@ -1394,6 +1394,8 @@
                                                TypeTy *Ty,
                                                SourceLocation RParen);
 
+  bool RequireCompleteDeclContext(const CXXScopeSpec &SS);
+
   /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
   /// global scope ('::').
   virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Mar 11 11:48:53 2009
@@ -17,6 +17,36 @@
 #include "llvm/ADT/STLExtras.h"
 using namespace clang;
 
+/// \brief Require that the context specified by SS be complete.
+///
+/// If SS refers to a type, this routine checks whether the type is
+/// complete enough (or can be made complete enough) for name lookup
+/// into the DeclContext. A type that is not yet completed can be
+/// considered "complete enough" if it is a class/struct/union/enum
+/// that is currently being defined. Or, if we have a type that names
+/// a class template specialization that is not a complete type, we
+/// will attempt to instantiate that class template.
+bool Sema::RequireCompleteDeclContext(const CXXScopeSpec &SS) {
+  if (!SS.isSet() || SS.isInvalid())
+    return false;
+  
+  DeclContext *DC = static_cast<DeclContext *>(SS.getScopeRep());
+  if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+    // If we're currently defining this type, then lookup into the
+    // type is okay: don't complain that it isn't complete yet.
+    const TagType *TagT = Context.getTypeDeclType(Tag)->getAsTagType();
+    if (TagT->isBeingDefined())
+      return false;
+
+    // The type must be complete.
+    return RequireCompleteType(SS.getRange().getBegin(),
+                               Context.getTypeDeclType(Tag),
+                               diag::err_incomplete_nested_name_spec,
+                               SS.getRange());
+  }
+
+  return false;
+}
 
 /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
 /// global scope ('::').

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 11 11:48:53 2009
@@ -1255,6 +1255,7 @@
                           D.getIdentifierLoc());
   } else { // Something like "int foo::x;"
     DC = static_cast<DeclContext*>(D.getCXXScopeSpec().getScopeRep());
+    // FIXME: RequireCompleteDeclContext(D.getCXXScopeSpec()); ?
     PrevDecl = LookupQualifiedName(DC, Name, LookupOrdinaryName, true);
 
     // C++ 7.3.1.2p2:
@@ -2895,6 +2896,7 @@
       goto CreateNewDecl;
     }
 
+    // FIXME: RequireCompleteDeclContext(SS)?
     DC = static_cast<DeclContext*>(SS.getScopeRep());
     SearchDC = DC;
     // Look-up name inside 'foo::'.

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Mar 11 11:48:53 2009
@@ -4344,6 +4344,8 @@
   if (!Dependent && !ArgTy->isRecordType())
     return Diag(TypeLoc, diag::err_offsetof_record_type) << ArgTy;
 
+  // FIXME: Does the type need to be complete?
+
   // Otherwise, create a null pointer as the base, and iteratively process
   // the offsetof designators.
   QualType ArgTyPtr = Context.getPointerType(ArgTy);

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Mar 11 11:48:53 2009
@@ -1035,7 +1035,7 @@
                        bool RedeclarationOnly, bool AllowBuiltinCreation,
                        SourceLocation Loc) {
   if (SS) {
-    if (SS->isInvalid())
+    if (SS->isInvalid() || RequireCompleteDeclContext(*SS))
       return LookupResult::CreateLookupResult(Context, 0);
 
     if (SS->isSet())

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Mar 11 11:48:53 2009
@@ -655,13 +655,44 @@
   // Start the definition of this instantiation.
   ClassTemplateSpec->startDefinition();
 
-  // FIXME: Create the injected-class-name for the
-  // instantiation. Should this be a typedef or something like it?
 
   // Instantiate the base class specifiers.
   if (InstantiateBaseSpecifiers(ClassTemplateSpec, Template))
     Invalid = true;
 
+  // FIXME: Create the injected-class-name for the
+  // instantiation. Should this be a typedef or something like it?
+
+  RecordDecl *Pattern = Template->getTemplatedDecl();
+
+  for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
+                              MemberEnd = Pattern->decls_end();
+       Member != MemberEnd; ++Member) {
+    if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(*Member)) {
+      // FIXME: Simplified instantiation of typedefs needs to be made
+      // "real".
+      QualType T = Typedef->getUnderlyingType();
+      if (T->isDependentType()) {
+        T = InstantiateType(T, ClassTemplateSpec->getTemplateArgs(),
+                            ClassTemplateSpec->getNumTemplateArgs(),
+                            Typedef->getLocation(),
+                            Typedef->getDeclName());
+        if (T.isNull()) {
+          Invalid = true;
+          T = Context.IntTy;
+        }
+      }
+       
+      // Create the new typedef
+      TypedefDecl *New 
+        = TypedefDecl::Create(Context, ClassTemplateSpec,
+                              Typedef->getLocation(),
+                              Typedef->getIdentifier(),
+                              T);
+      ClassTemplateSpec->addDecl(New);
+    }
+  }
+
   // FIXME: Instantiate all of the members.
   
   // Add any implicitly-declared members that we might need.

Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=66662&r1=66661&r2=66662&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Wed Mar 11 11:48:53 2009
@@ -1,5 +1,4 @@
-// RUN: clang -fsyntax-only -verify -std=c++98 %s 
-// fails due to exact diagnostic matching
+// RUN: clang -fsyntax-only -std=c++98 -verify %s 
 namespace A {
   struct C {
     static int cx;
@@ -151,5 +150,10 @@
 
 void N::f() { } // okay
 
+struct Y;  // expected-note{{forward declaration of 'struct Y'}}
+Y::foo y; // expected-error{{incomplete type 'struct Y' named in nested name specifier}} \
+         // FIXME: ugly: expected-error{{invalid token after top level declarator}}
+
 X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \
       // expected-error{{expected function body after function declarator}}
+

Added: cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp?rev=66662&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-typedef.cpp Wed Mar 11 11:48:53 2009
@@ -0,0 +1,15 @@
+// RUN: clang -fsyntax-only -verify %s
+
+template<typename T>
+struct add_pointer {
+  typedef T* type; // expected-error{{'type' declared as a pointer to a reference}}
+};
+
+add_pointer<int>::type test1(int * ptr) { return ptr; }
+
+add_pointer<float>::type test2(int * ptr) { 
+  return ptr; // expected-error{{incompatible type returning 'int *', expected 'type' (aka 'float *')}}
+}
+
+add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}}
+test3(); // FIXME: expected-error{{invalid token after top level declarator}}





More information about the cfe-commits mailing list