]> granicus.if.org Git - clang/commitdiff
Delay checking of typedefs of dependent types. Fixes PR11630.
authorRafael Espindola <rafael.espindola@gmail.com>
Mon, 26 Dec 2011 22:42:47 +0000 (22:42 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Mon, 26 Dec 2011 22:42:47 +0000 (22:42 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147281 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/typedef-redecl.cpp

index 9b244cdc84f55545f2017d0dccb51f02fe5633cb..d9f9ab5cf0018c76777fe55a8402d595c771ade0 100644 (file)
@@ -1326,6 +1326,7 @@ public:
   /// Subroutines of ActOnDeclarator().
   TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
                                 TypeSourceInfo *TInfo);
+  bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New);
   void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls);
   bool MergeFunctionDecl(FunctionDecl *New, Decl *Old);
   bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old);
index 00c6b9fcf093933492586021f84e162b1231bf41..a13f1826b6fcb20028bfa041a95ed958616685b5 100644 (file)
@@ -1368,6 +1368,30 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid,
   return New;
 }
 
+bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
+  QualType OldType;
+  if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
+    OldType = OldTypedef->getUnderlyingType();
+  else
+    OldType = Context.getTypeDeclType(Old);
+  QualType NewType = New->getUnderlyingType();
+
+  if (OldType != NewType &&
+      !OldType->isDependentType() &&
+      !NewType->isDependentType() &&
+      Context.getCanonicalType(OldType) !=
+      Context.getCanonicalType(NewType)) {
+    int Kind = isa<TypeAliasDecl>(Old) ? 1 : 0;
+    Diag(New->getLocation(), diag::err_redefinition_different_typedef)
+      << Kind << NewType << OldType;
+    if (Old->getLocation().isValid())
+      Diag(Old->getLocation(), diag::note_previous_definition);
+    New->setInvalidDecl();
+    return true;
+  }
+  return false;
+}
+
 /// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the
 /// same name and scope as a previous declaration 'Old'.  Figure out
 /// how to resolve this situation, merging decls or emitting
@@ -1426,28 +1450,10 @@ void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) {
   if (Old->isInvalidDecl())
     return New->setInvalidDecl();
 
-  // Determine the "old" type we'll use for checking and diagnostics.
-  QualType OldType;
-  if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old))
-    OldType = OldTypedef->getUnderlyingType();
-  else
-    OldType = Context.getTypeDeclType(Old);
-
   // If the typedef types are not identical, reject them in all languages and
   // with any extensions enabled.
-
-  if (OldType != New->getUnderlyingType() &&
-      Context.getCanonicalType(OldType) !=
-      Context.getCanonicalType(New->getUnderlyingType())) {
-    int Kind = 0;
-    if (isa<TypeAliasDecl>(Old))
-      Kind = 1;
-    Diag(New->getLocation(), diag::err_redefinition_different_typedef)
-      << Kind << New->getUnderlyingType() << OldType;
-    if (Old->getLocation().isValid())
-      Diag(Old->getLocation(), diag::note_previous_definition);
-    return New->setInvalidDecl();
-  }
+  if (isIncompatibleTypedef(Old, New))
+    return;
 
   // The types match.  Link up the redeclaration chain if the old
   // declaration was a typedef.
index 53adf68cd97c6cae9be412a73e4057ba252b4dcf..1f879838052ee345109df6f3f42865736ea5183b 100644 (file)
@@ -169,7 +169,12 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D,
     if (!InstPrev)
       return 0;
 
-    Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev));
+    TypedefNameDecl *InstPrevTypedef = cast<TypedefNameDecl>(InstPrev);
+
+    // If the typedef types are not identical, reject them.
+    SemaRef.isIncompatibleTypedef(InstPrevTypedef, Typedef);
+
+    Typedef->setPreviousDeclaration(InstPrevTypedef);
   }
 
   SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef);
index 31de9c00c105aa5f5b04c6754cdf71879fb18e84..b53bcd2b45800f2b9a856a29bf6c3c79557edb3a 100644 (file)
@@ -59,3 +59,37 @@ template<typename T>
 typedef T f(T t) { return t; } // expected-error {{function definition declared 'typedef'}}
 int k = f(0);
 int k2 = k;
+
+namespace PR11630 {
+  template <class T>
+  struct S
+  {
+    static const unsigned C = 1;
+    static void f()
+    {
+      typedef int q[C == 1 ? 1 : -1]; // expected-note{{previous definition is here}}
+      typedef int q[C >= 1 ? 2 : -2]; // expected-error{{typedef redefinition with different types ('int [2]' vs 'int [1]')}}
+      typedef int n[C == 1 ? 1 : -1];
+      typedef int n[C >= 1 ? 1 : -1];
+    }
+  };
+
+  template <int T>
+  struct S2
+  {
+    static void f()
+    {
+      typedef int q[1];  // expected-note{{previous definition is here}}
+      typedef int q[T];  // expected-error{{typedef redefinition with different types ('int [2]' vs 'int [1]')}}
+    }
+  };
+
+  void f() {
+    S<int> a;
+    a.f(); // expected-note{{in instantiation of member function 'PR11630::S<int>::f' requested here}}
+    S2<1> b;
+    b.f();
+    S2<2> b2;
+    b2.f(); // expected-note{{in instantiation of member function 'PR11630::S2<2>::f' requested here}}
+  }
+}