diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 69e9ff9e9c6f..d5ca944c1d95 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp index 06c6695008e0..95fb7885f7cd 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.typedef/p4.cpp +++ b/clang/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}}