From 52b26713bebf3a6724d924a10719fb9ab936e694 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Thu, 27 Oct 2016 08:37:14 +0000 Subject: [PATCH] Mark invalid RecordDecls as completed. Sema::ActOnTag creates TagDecls for records. However, if those record declarations are invalid, and the parser is in C++ mode, it would silently drop the TagDecl (and leave it as "beingDefined"). The problem is that other code (e.g. the ASTWriter) will serialize all types, and expects them to be complete. So, leaving them open would result in failing asserts. Fixes PR20320 Differential Revision: http://reviews.llvm.org/D21176 llvm-svn: 285275 --- clang/lib/Sema/SemaDecl.cpp | 9 ++++++++- clang/test/Index/pr20320.cpp | 2 ++ clang/test/Index/pr20320.h | 14 ++++++++++++++ clang/test/SemaCXX/conversion-function.cpp | 6 +++++- 4 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 clang/test/Index/pr20320.cpp create mode 100644 clang/test/Index/pr20320.h diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e9e0f5e214d2..c8973ae100e7 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13386,7 +13386,14 @@ CreateNewDecl: OwnedDecl = true; // In C++, don't return an invalid declaration. We can't recover well from // the cases where we make the type anonymous. - return (Invalid && getLangOpts().CPlusPlus) ? nullptr : New; + if (Invalid && getLangOpts().CPlusPlus) { + if (New->isBeingDefined()) + if (auto RD = dyn_cast(New)) + RD->completeDefinition(); + return nullptr; + } else { + return New; + } } void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { diff --git a/clang/test/Index/pr20320.cpp b/clang/test/Index/pr20320.cpp new file mode 100644 index 000000000000..cb54cea642a3 --- /dev/null +++ b/clang/test/Index/pr20320.cpp @@ -0,0 +1,2 @@ +// RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -x c++ %s +#include "pr20320.h" diff --git a/clang/test/Index/pr20320.h b/clang/test/Index/pr20320.h new file mode 100644 index 000000000000..9dbb7303df2d --- /dev/null +++ b/clang/test/Index/pr20320.h @@ -0,0 +1,14 @@ +#ifndef pr20320_h +#define pr20320_h + +template<> +struct S< ::Number::One> +{ +}; + +template<> +struct S< ::Number::Two> +{ +}; + +#endif diff --git a/clang/test/SemaCXX/conversion-function.cpp b/clang/test/SemaCXX/conversion-function.cpp index 3f494cce8ce3..c725a0d5b7c1 100644 --- a/clang/test/SemaCXX/conversion-function.cpp +++ b/clang/test/SemaCXX/conversion-function.cpp @@ -434,8 +434,12 @@ namespace PR18234 { struct A { operator enum E { e } (); // expected-error {{'PR18234::A::E' cannot be defined in a type specifier}} operator struct S { int n; } (); // expected-error {{'PR18234::A::S' cannot be defined in a type specifier}} + // expected-note@-1 {{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'struct A' to 'const PR18234::A::S &' for 1st argument}} +#if __cplusplus >= 201103L + // expected-note@-3 {{candidate constructor (the implicit move constructor) not viable: no known conversion from 'struct A' to 'PR18234::A::S &&' for 1st argument}} +#endif } a; - A::S s = a; + A::S s = a; // expected-error {{no viable conversion from 'struct A' to 'A::S'}} A::E e = a; // expected-note {{here}} bool k1 = e == A::e; // expected-error {{no member named 'e'}} bool k2 = e.n == 0;