From: Douglas Gregor Date: Mon, 11 Jan 2010 21:54:40 +0000 (+0000) Subject: Allow redefinitions of typedef-names within class scope when the type X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=93dda720a6f5b67ea997c8d98414f90ec362b43c;p=clang Allow redefinitions of typedef-names within class scope when the type they redefine is a class-name but not a typedef-name, per C++0x [dcl.typedef]p4. The code in the test was valid C++98 and is valid C++0x, but an unintended consequence of DR56 made it ill-formed in C++03 (which we were luck enough to implement). Fixes PR5455. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93188 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 69e9ff9e9c..d5ca944c1d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -803,13 +803,38 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { if (getLangOptions().Microsoft) return; - // C++ [dcl.typedef]p2: - // In a given non-class scope, a typedef specifier can be used to - // redefine the name of any type declared in that scope to refer - // to the type to which it already refers. if (getLangOptions().CPlusPlus) { + // C++ [dcl.typedef]p2: + // In a given non-class scope, a typedef specifier can be used to + // redefine the name of any type declared in that scope to refer + // to the type to which it already refers. if (!isa(CurContext)) return; + + // C++0x [dcl.typedef]p4: + // In a given class scope, a typedef specifier can be used to redefine + // any class-name declared in that scope that is not also a typedef-name + // to refer to the type to which it already refers. + // + // This wording came in via DR424, which was a correction to the + // wording in DR56, which accidentally banned code like: + // + // struct S { + // typedef struct A { } A; + // }; + // + // in the C++03 standard. We implement the C++0x semantics, which + // allow the above but disallow + // + // struct S { + // typedef int I; + // typedef int I; + // }; + // + // since that was the intent of DR56. + if (New->getUnderlyingType()->getAs()) + return; + Diag(New->getLocation(), diag::err_redefinition) << New->getDeclName(); Diag(Old->getLocation(), diag::note_previous_definition); diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp index 06c6695008..95fb7885f7 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -verify %s -// XFAIL: * struct S { typedef struct A {} A; // expected-note {{previous definition is here}}