[cfe-commits] r81504 - in /cfe/trunk: include/clang/Parse/Action.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiate.cpp test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp

John McCall rjmccall at apple.com
Thu Sep 10 21:59:26 PDT 2009


Author: rjmccall
Date: Thu Sep 10 23:59:25 2009
New Revision: 81504

URL: http://llvm.org/viewvc/llvm-project?rev=81504&view=rev
Log:
Support elaborated dependent types and diagnose tag mismatches.


Added:
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=81504&r1=81503&r2=81504&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Thu Sep 10 23:59:25 2009
@@ -522,10 +522,34 @@
                              IdentifierInfo *Name, SourceLocation NameLoc,
                              AttributeList *Attr, AccessSpecifier AS,
                              MultiTemplateParamsArg TemplateParameterLists,
-                             bool &OwnedDecl) {
+                             bool &OwnedDecl, bool &IsDependent) {
     return DeclPtrTy();
   }
 
+  /// Acts on a reference to a dependent tag name.  This arises in
+  /// cases like:
+  ///
+  ///    template <class T> class A;
+  ///    template <class T> class B {
+  ///      friend class A<T>::M;  // here
+  ///    };
+  ///
+  /// \param TagSpec an instance of DeclSpec::TST corresponding to the
+  /// tag specifier.
+  ///
+  /// \param TUK the tag use kind (either TUK_Friend or TUK_Reference)
+  ///
+  /// \param SS the scope specifier (always defined)
+  virtual TypeResult ActOnDependentTag(Scope *S,
+                                       unsigned TagSpec,
+                                       TagUseKind TUK,
+                                       const CXXScopeSpec &SS,
+                                       IdentifierInfo *Name,
+                                       SourceLocation KWLoc,
+                                       SourceLocation NameLoc) {
+    return TypeResult();
+  }
+
   /// Act on @defs() element found when parsing a structure.  ClassName is the
   /// name of the referenced class.
   virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=81504&r1=81503&r2=81504&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Sep 10 23:59:25 2009
@@ -1641,10 +1641,12 @@
   else
     TUK = Action::TUK_Reference;
   bool Owned = false;
+  bool IsDependent = false;
   DeclPtrTy TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TUK,
                                        StartLoc, SS, Name, NameLoc, Attr, AS,
                                        Action::MultiTemplateParamsArg(Actions),
-                                       Owned);
+                                       Owned, IsDependent);
+  assert(!IsDependent && "didn't expect dependent enum");
 
   if (Tok.is(tok::l_brace))
     ParseEnumBody(StartLoc, TagDecl);

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=81504&r1=81503&r2=81504&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Sep 10 23:59:25 2009
@@ -619,7 +619,8 @@
   }
 
   // Create the tag portion of the class or class template.
-  Action::DeclResult TagOrTempResult;
+  Action::DeclResult TagOrTempResult = true; // invalid
+  Action::TypeResult TypeResult = true; // invalid
   TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;
 
   // FIXME: When TUK == TUK_Reference and we have a template-id, we need
@@ -651,7 +652,7 @@
                                              TemplateId->RAngleLoc,
                                              Attr);
     } else if (TUK == Action::TUK_Reference || TUK == Action::TUK_Friend) {
-      Action::TypeResult Type
+      TypeResult
         = Actions.ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
                                       TemplateId->TemplateNameLoc,
                                       TemplateId->LAngleLoc,
@@ -659,23 +660,8 @@
                                       TemplateId->getTemplateArgLocations(),
                                       TemplateId->RAngleLoc);
 
-      Type = Actions.ActOnTagTemplateIdType(Type, TUK, TagType, StartLoc);
-
-      TemplateId->Destroy();
-
-      if (Type.isInvalid()) {
-        DS.SetTypeSpecError();
-        return;
-      }
-
-      const char *PrevSpec = 0;
-      unsigned DiagID;
-      if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, PrevSpec,
-                             DiagID, Type.get()))
-        Diag(StartLoc, DiagID) << PrevSpec;
-
-      return;
-
+      TypeResult = Actions.ActOnTagTemplateIdType(TypeResult, TUK,
+                                                  TagType, StartLoc);
     } else {
       // This is an explicit specialization or a class template
       // partial specialization.
@@ -746,13 +732,21 @@
       // FIXME: Diagnose this particular error.
     }
 
+    bool IsDependent = false;
+
     // Declaration or definition of a class type
     TagOrTempResult = Actions.ActOnTag(CurScope, TagType, TUK, StartLoc, SS,
                                        Name, NameLoc, Attr, AS,
                                   Action::MultiTemplateParamsArg(Actions,
                                     TemplateParams? &(*TemplateParams)[0] : 0,
                                     TemplateParams? TemplateParams->size() : 0),
-                                       Owned);
+                                       Owned, IsDependent);
+
+    // If ActOnTag said the type was dependent, try again with the
+    // less common call.
+    if (IsDependent)
+      TypeResult = Actions.ActOnDependentTag(CurScope, TagType, TUK,
+                                             SS, Name, StartLoc, NameLoc);      
   }
 
   // Parse the optional base clause (C++ only).
@@ -771,15 +765,23 @@
     Diag(Tok, diag::err_expected_lbrace);
   }
 
-  if (TagOrTempResult.isInvalid()) {
+  void *Result;
+  if (!TypeResult.isInvalid()) {
+    TagType = DeclSpec::TST_typename;
+    Result = TypeResult.get();
+    Owned = false;
+  } else if (!TagOrTempResult.isInvalid()) {
+    Result = TagOrTempResult.get().getAs<void>();
+  } else {
     DS.SetTypeSpecError();
     return;
   }
 
   const char *PrevSpec = 0;
   unsigned DiagID;
+
   if (DS.SetTypeSpecType(TagType, StartLoc, PrevSpec, DiagID,
-                         TagOrTempResult.get().getAs<void>(), Owned))
+                         Result, Owned))
     Diag(StartLoc, DiagID) << PrevSpec;
 }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Sep 10 23:59:25 2009
@@ -609,7 +609,15 @@
                              IdentifierInfo *Name, SourceLocation NameLoc,
                              AttributeList *Attr, AccessSpecifier AS,
                              MultiTemplateParamsArg TemplateParameterLists,
-                             bool &OwnedDecl);
+                             bool &OwnedDecl, bool &IsDependent);
+
+  virtual TypeResult ActOnDependentTag(Scope *S,
+                                       unsigned TagSpec,
+                                       TagUseKind TUK,
+                                       const CXXScopeSpec &SS,
+                                       IdentifierInfo *Name,
+                                       SourceLocation TagLoc,
+                                       SourceLocation NameLoc);
 
   virtual void ActOnDefs(Scope *S, DeclPtrTy TagD, SourceLocation DeclStart,
                          IdentifierInfo *ClassName,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Sep 10 23:59:25 2009
@@ -3988,7 +3988,7 @@
                                IdentifierInfo *Name, SourceLocation NameLoc,
                                AttributeList *Attr, AccessSpecifier AS,
                                MultiTemplateParamsArg TemplateParameterLists,
-                               bool &OwnedDecl) {
+                               bool &OwnedDecl, bool &IsDependent) {
   // If this is not a definition, it must have a name.
   assert((Name != 0 || TUK == TUK_Definition) &&
          "Nameless record must be a definition!");
@@ -4034,6 +4034,16 @@
       goto CreateNewDecl;
     }
 
+    // If this is a friend or a reference to a class in a dependent
+    // context, don't try to make a decl for it.
+    if (TUK == TUK_Friend || TUK == TUK_Reference) {
+      DC = computeDeclContext(SS, false);
+      if (!DC) {
+        IsDependent = true;
+        return DeclPtrTy();
+      }
+    }
+
     if (RequireCompleteDeclContext(SS))
       return DeclPtrTy::make((Decl *)0);
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Sep 10 23:59:25 2009
@@ -1159,9 +1159,10 @@
 
     if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) {
       Diag(TagLoc, diag::err_use_with_wrong_tag)
-        << Id
+        << Type
         << CodeModificationHint::CreateReplacement(SourceRange(TagLoc),
                                                    D->getKindName());
+      Diag(D->getLocation(), diag::note_previous_use);
     }
   }
 
@@ -3058,9 +3059,13 @@
                                  AttributeList *Attr) {
 
   bool Owned = false;
+  bool IsDependent = false;
   DeclPtrTy TagD = ActOnTag(S, TagSpec, Action::TUK_Reference,
                             KWLoc, SS, Name, NameLoc, Attr, AS_none,
-                            MultiTemplateParamsArg(*this, 0, 0), Owned);
+                            MultiTemplateParamsArg(*this, 0, 0),
+                            Owned, IsDependent);
+  assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
+
   if (!TagD)
     return true;
 
@@ -3124,6 +3129,28 @@
 }
 
 Sema::TypeResult
+Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
+                        const CXXScopeSpec &SS, IdentifierInfo *Name,
+                        SourceLocation TagLoc, SourceLocation NameLoc) {
+  // This has to hold, because SS is expected to be defined.
+  assert(Name && "Expected a name in a dependent tag");
+
+  NestedNameSpecifier *NNS
+    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  if (!NNS)
+    return true;
+
+  QualType T = CheckTypenameType(NNS, *Name, SourceRange(TagLoc, NameLoc));
+  if (T.isNull())
+    return true;
+
+  TagDecl::TagKind TagKind = TagDecl::getTagKindForTypeSpec(TagSpec);
+  QualType ElabType = Context.getElaboratedType(T, TagKind);
+
+  return ElabType.getAsOpaquePtr();
+}
+
+Sema::TypeResult
 Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
                         const IdentifierInfo &II, SourceLocation IdLoc) {
   NestedNameSpecifier *NNS

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Sep 10 23:59:25 2009
@@ -391,6 +391,10 @@
                                   IdentifierInfo *Name,
                                   SourceLocation Loc, SourceRange TypeRange);
 
+    /// \brief Check for tag mismatches when instantiating an
+    /// elaborated type.
+    QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag);
+
     Sema::OwningExprResult TransformPredefinedExpr(PredefinedExpr *E);
     Sema::OwningExprResult TransformDeclRefExpr(DeclRefExpr *E);
 
@@ -451,7 +455,33 @@
   return Var;
 }
 
-Sema::OwningExprResult
+QualType
+TemplateInstantiator::RebuildElaboratedType(QualType T,
+                                            ElaboratedType::TagKind Tag) {
+  if (const TagType *TT = T->getAs<TagType>()) {
+    TagDecl* TD = TT->getDecl();
+
+    // FIXME: this location is very wrong;  we really need typelocs.
+    SourceLocation TagLocation = TD->getTagKeywordLoc();
+
+    // FIXME: type might be anonymous.
+    IdentifierInfo *Id = TD->getIdentifier();
+
+    // TODO: should we even warn on struct/class mismatches for this?  Seems
+    // like it's likely to produce a lot of spurious errors.
+    if (!SemaRef.isAcceptableTagRedeclaration(TD, Tag, TagLocation, *Id)) {
+      SemaRef.Diag(TagLocation, diag::err_use_with_wrong_tag)
+        << Id
+        << CodeModificationHint::CreateReplacement(SourceRange(TagLocation),
+                                                   TD->getKindName());
+      SemaRef.Diag(TD->getLocation(), diag::note_previous_use);
+    }
+  }
+
+  return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(T, Tag);
+}
+
+Sema::OwningExprResult 
 TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
   if (!E->isTypeDependent())
     return SemaRef.Owned(E->Retain());

Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp?rev=81504&r1=81503&r2=81504&view=diff

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.elab/templateid.cpp Thu Sep 10 23:59:25 2009
@@ -11,7 +11,9 @@
   template <typename> void Ident();
 
   class Ident<int> AIdent; // expected-error {{refers to a function template}}
-  class ::Ident<int> AnotherIdent;
+
+  // FIXME: this note should be on the template declaration, not the point of instantiation
+  class ::Ident<int> AnotherIdent; // expected-note {{previous use is here}}
 }
 
 class Ident<int> GlobalIdent;

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp?rev=81504&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp Thu Sep 10 23:59:25 2009
@@ -0,0 +1,61 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+class A {}; // expected-note 3 {{previous use is here}}
+
+void a1(struct A);
+void a2(class A);
+void a3(union A); // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+void a4(enum A); // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+
+class A1 {
+  friend struct A;
+  friend class A;
+  friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+
+  // FIXME: a better error would be something like 'enum types cannot be friends'
+  friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}}
+};
+
+template <class T> struct B {
+  class Member {}; // expected-note 2 {{previous use is here}}
+};
+
+template <> class B<int> {
+  // no type Member
+};
+
+template <> struct B<A> {
+  // FIXME: the error here should be associated with the use at "void foo..."
+  union Member { // expected-note 4 {{previous use is here}} expected-error {{tag type that does not match previous declaration}}
+    void* a;
+  };
+};
+
+// FIXME: this note should be on the template declaration, not the point of instantiation
+void b1(struct B<float>); // expected-note {{previous use is here}}
+void b2(class B<float>);
+void b3(union B<float>); // expected-error {{use of 'B<float>' with tag type that does not match previous declaration}}
+//void b4(enum B<float>); // this just doesn't parse; you can't template an enum directly
+
+void c1(struct B<float>::Member);
+void c2(class B<float>::Member);
+void c3(union B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+void c4(enum B<float>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+
+void d1(struct B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+void d2(class B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+void d3(union B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+void d4(enum B<int>::Member); // expected-error {{'Member' does not name a tag member in the specified scope}}
+
+void e1(struct B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+void e2(class B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+void e3(union B<A>::Member);
+void e4(enum B<A>::Member); // expected-error {{use of 'Member' with tag type that does not match previous declaration}}
+
+template <class T> struct C {
+  void foo(class B<T>::Member); // expected-error{{no type named 'Member' in 'B'}}
+};
+
+C<float> f1;
+C<int> f2; // expected-note {{in instantiation of template class}}
+C<A> f3; // expected-note {{in instantiation of template class}}





More information about the cfe-commits mailing list