From 5df37bd0242e838e465f0bd51a70af424d152053 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 26 Dec 2011 22:42:47 +0000 Subject: [PATCH] Delay checking of typedefs of dependent types. Fixes PR11630. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147281 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 1 + lib/Sema/SemaDecl.cpp | 46 +++++++++++++----------- lib/Sema/SemaTemplateInstantiateDecl.cpp | 7 +++- test/SemaCXX/typedef-redecl.cpp | 34 ++++++++++++++++++ 4 files changed, 67 insertions(+), 21 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 9b244cdc84..d9f9ab5cf0 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 00c6b9fcf0..a13f1826b6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(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(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(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(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. diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 53adf68cd9..1f87983805 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -169,7 +169,12 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, if (!InstPrev) return 0; - Typedef->setPreviousDeclaration(cast(InstPrev)); + TypedefNameDecl *InstPrevTypedef = cast(InstPrev); + + // If the typedef types are not identical, reject them. + SemaRef.isIncompatibleTypedef(InstPrevTypedef, Typedef); + + Typedef->setPreviousDeclaration(InstPrevTypedef); } SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); diff --git a/test/SemaCXX/typedef-redecl.cpp b/test/SemaCXX/typedef-redecl.cpp index 31de9c00c1..b53bcd2b45 100644 --- a/test/SemaCXX/typedef-redecl.cpp +++ b/test/SemaCXX/typedef-redecl.cpp @@ -59,3 +59,37 @@ template typedef T f(T t) { return t; } // expected-error {{function definition declared 'typedef'}} int k = f(0); int k2 = k; + +namespace PR11630 { + template + 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 + 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 a; + a.f(); // expected-note{{in instantiation of member function 'PR11630::S::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}} + } +} -- 2.40.0