]> granicus.if.org Git - clang/commitdiff
Don't assert when instantiating member references to fields in anonymous structs.
authorAnders Carlsson <andersca@mac.com>
Tue, 1 Sep 2009 04:26:58 +0000 (04:26 +0000)
committerAnders Carlsson <andersca@mac.com>
Tue, 1 Sep 2009 04:26:58 +0000 (04:26 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80657 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/TreeTransform.h
test/SemaTemplate/instantiate-anonymous-union.cpp

index 5021655f331b20d6f235df7d2fab528b1985c685..01da133c07c53f324a7ac67c460afabf46ec433b 100644 (file)
@@ -196,6 +196,8 @@ class ASTContext {
   llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>
     InstantiatedFromUnresolvedUsingDecl;
   
+  llvm::DenseMap<FieldDecl *, FieldDecl *> InstantiatedFromUnnamedFieldDecl;
+  
   TranslationUnitDecl *TUDecl;
 
   /// SourceMgr - The associated SourceManager object.
@@ -267,12 +269,23 @@ public:
   /// the static data member template \p Tmpl of a class template.
   void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl);  
   
+  /// \brief If this using decl is instantiated from an unresolved using decl,
+  /// return it.
   UnresolvedUsingDecl *getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD);
-  void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD,
-                                              UnresolvedUsingDecl *UUD);
+
+  /// \brief Note that the using decl \p Inst is an instantiation of
+  /// the unresolved using decl \p Tmpl of a class template.
+  void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *Inst,
+                                              UnresolvedUsingDecl *Tmpl);
+  
+  
+  FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field);
+  
+  void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl);
   
   TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; }
 
+  
   const char *getCommentForDecl(const Decl *D);
   
   // Builtin Types.
index eebb11da998dd671885a6798ae22a4a67e5c1cbe..1143b305add0e539bf5f3cecff72f2881450aad3 100644 (file)
@@ -260,6 +260,25 @@ ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD,
   InstantiatedFromUnresolvedUsingDecl[UD] = UUD;
 }
 
+FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) {
+  llvm::DenseMap<FieldDecl *, FieldDecl *>::iterator Pos
+    = InstantiatedFromUnnamedFieldDecl.find(Field);
+  if (Pos == InstantiatedFromUnnamedFieldDecl.end())
+    return 0;
+  
+  return Pos->second;
+}
+
+void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
+                                                     FieldDecl *Tmpl) {
+  assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed");
+  assert(!Tmpl->getDeclName() && "Template field decl is not unnamed");
+  assert(!InstantiatedFromUnnamedFieldDecl[Inst] &&
+         "Already noted what unnamed field was instantiated from");
+  
+  InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
+}
+
 namespace {
   class BeforeInTranslationUnit 
     : std::binary_function<SourceRange, SourceRange, bool> {
index c5b2894c4980182dc9e30728cc9fc6d57438b457..84e464aba300817f7eefa7e6371e075c4bb83c52 100644 (file)
@@ -245,6 +245,11 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
     if (Invalid)
       Field->setInvalidDecl();
     
+    if (!Field->getDeclName()) {
+      // Keep track of where this decl came from.
+      SemaRef.Context.setInstantiatedFromUnnamedFieldDecl(Field, D);
+    }
+    
     Owner->addDecl(Field);
   }
 
@@ -441,6 +446,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
   if (Decl::FriendObjectKind FOK = D->getFriendObjectKind())
     Record->setObjectOfFriendDecl(FOK == Decl::FOK_Declared);
 
+  Record->setAnonymousStructOrUnion(D->isAnonymousStructOrUnion());
+
   Owner->addDecl(Record);
   return Record;
 }
@@ -1274,8 +1281,14 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) {
   if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other))
     return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp);
 
-  // FIXME: How can we find instantiations of anonymous unions?
-
+  if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) {
+    if (!Field->getDeclName()) {
+      // This is an unnamed field.
+      return Ctx.getInstantiatedFromUnnamedFieldDecl(Field) == 
+        cast<FieldDecl>(D);
+    }
+  }
+  
   return D->getDeclName() && isa<NamedDecl>(Other) &&
     D->getDeclName() == cast<NamedDecl>(Other)->getDeclName();
 }
index 386a2c6d80644862bdfeb9068a0d468c47095077..f1888c87a43f073c1a06ec1a99e171e1a92b5cac 100644 (file)
@@ -840,6 +840,17 @@ public:
                                      SourceRange QualifierRange,
                                      SourceLocation MemberLoc,
                                      NamedDecl *Member) {
+    if (!Member->getDeclName()) {
+      // We have a reference to an unnamed field.
+      assert(!Qualifier && "Can't have an unnamed field with a qualifier!");
+      
+      MemberExpr *ME = 
+        new (getSema().Context) MemberExpr(Base.takeAs<Expr>(), isArrow,
+                                           Member, MemberLoc,
+                                           cast<FieldDecl>(Member)->getType());
+      return getSema().Owned(ME);
+    }
+      
     CXXScopeSpec SS;
     if (Qualifier) {
       SS.setRange(QualifierRange);
index 4eb5b0c24cb0e3ac19bb116b51e662c39f106e12..9c2467be64533bffa67590a0f09149e3ffb16cd6 100644 (file)
@@ -6,3 +6,16 @@ template <typename T> class A { struct { }; };
 
 A<int> a0;
 
+template <typename T> struct B {
+  union {
+    int a;
+    void* b;
+  };
+    
+  void f() {
+    a = 10;
+    b = 0;
+  }
+};
+
+B<int> b0;