[clang] 7ae1b4a - Implement P1766R1: diagnose giving non-C-compatible classes a typedef name for linkage purposes.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 7 11:47:48 PST 2020
Author: Richard Smith
Date: 2020-02-07T11:47:37-08:00
New Revision: 7ae1b4a0ce9c7f269cf3069e41496a78e3f28d49
URL: https://github.com/llvm/llvm-project/commit/7ae1b4a0ce9c7f269cf3069e41496a78e3f28d49
DIFF: https://github.com/llvm/llvm-project/commit/7ae1b4a0ce9c7f269cf3069e41496a78e3f28d49.diff
LOG: Implement P1766R1: diagnose giving non-C-compatible classes a typedef name for linkage purposes.
Summary:
Due to a recent (but retroactive) C++ rule change, only sufficiently
C-compatible classes are permitted to be given a typedef name for
linkage purposes. Add an enabled-by-default warning for these cases, and
rephrase our existing error for the case where we encounter the typedef
name for linkage after we've already computed and used a wrong linkage
in terms of the new rule.
Reviewers: rjmccall
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D74103
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaDecl.cpp
clang/test/Analysis/inlining/eager-reclamation-path-notes.cpp
clang/test/Analysis/padding_cpp.cpp
clang/test/Analysis/padding_message.cpp
clang/test/CXX/class/class.local/p4.cpp
clang/test/CXX/class/class.union/p2-0x.cpp
clang/test/CXX/drs/dr4xx.cpp
clang/test/Modules/submodules-merge-defs.cpp
clang/test/OpenMP/target_map_codegen.cpp
clang/test/SemaCXX/anonymous-struct.cpp
clang/test/SemaCXX/linkage.cpp
clang/test/SemaCXX/linkage2.cpp
clang/test/SemaCXX/undefined-internal.cpp
clang/test/SemaCXX/warn-unused-filescoped.cpp
clang/test/SemaCXX/warn-unused-local-typedef.cpp
clang/test/SemaTemplate/instantiate-function-2.cpp
clang/www/cxx_status.html
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 856effd19718..d24cd85673c6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -103,6 +103,43 @@ C11 Feature Support
C++ Language Changes in Clang
-----------------------------
+- Clang now implements a restriction on giving non-C-compatible anonymous
+ structs a typedef name for linkage purposes, as described in C++ committee
+ paper `P1766R1 <http://wg21.link/p1766r1>`. This paper was adopted by the
+ C++ committee as a Defect Report resolution, so it is applied retroactively
+ to all C++ standard versions. This affects code such as:
+
+ .. code-block:: c++
+
+ typedef struct {
+ int f() { return 0; }
+ } S;
+
+ Previous versions of Clang rejected some constructs of this form
+ (specifically, where the linkage of the type happened to be computed
+ before the parser reached the typedef name); those cases are still rejected
+ in Clang 11. In addition, cases that previous versions of Clang did not
+ reject now produce an extension warning. This warning can be disabled with
+ the warning flag ``-Wno-non-c-typedef-for-linkage``.
+
+ Affected code should be updated to provide a tag name for the anonymous
+ struct:
+
+ .. code-block:: c++
+
+ struct S {
+ int f() { return 0; }
+ };
+
+ If the code is shared with a C compilation (for example, if the parts that
+ are not C-compatible are guarded with ``#ifdef __cplusplus``), the typedef
+ declaration should be retained, but a tag name should still be provided:
+
+ .. code-block:: c++
+
+ typedef struct S {
+ int f() { return 0; }
+ } S;
C++1z Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index bd5bfa3e122b..9de60d3a8d27 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -788,10 +788,27 @@ def ext_no_declarators : ExtWarn<"declaration does not declare anything">,
def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">,
InGroup<MissingDeclarations>;
def err_typedef_not_identifier : Error<"typedef name must be an identifier">;
-def err_typedef_changes_linkage : Error<"unsupported: typedef changes linkage"
- " of anonymous type, but linkage was already computed">;
-def note_typedef_changes_linkage : Note<"use a tag name here to establish "
- "linkage prior to definition">;
+
+def ext_non_c_like_anon_struct_in_typedef : ExtWarn<
+ "anonymous non-C-compatible type given name for linkage purposes "
+ "by %select{typedef|alias}0 declaration; "
+ "add a tag name here">, InGroup<DiagGroup<"non-c-typedef-for-linkage">>;
+def err_non_c_like_anon_struct_in_typedef : Error<
+ "anonymous non-C-compatible type given name for linkage purposes "
+ "by %select{typedef|alias}0 declaration after its linkage was computed; "
+ "add a tag name here to establish linkage prior to definition">;
+def err_typedef_changes_linkage : Error<
+ "unsupported: anonymous type given name for linkage purposes "
+ "by %select{typedef|alias}0 declaration after its linkage was computed; "
+ "add a tag name here to establish linkage prior to definition">;
+def note_non_c_like_anon_struct : Note<
+ "type is not C-compatible due to this "
+ "%select{base class|default member initializer|lambda expression|"
+ "friend declaration|member declaration}0">;
+def note_typedef_for_linkage_here : Note<
+ "type is given name %0 for linkage purposes by this "
+ "%select{typedef|alias}1 declaration">;
+
def err_statically_allocated_object : Error<
"interface type cannot be statically allocated">;
def err_object_cannot_be_passed_returned_by_value : Error<
@@ -1796,8 +1813,13 @@ def note_nontrivial_objc_ownership : Note<
"because type %0 has a member with %select{no|no|__strong|__weak|"
"__autoreleasing}1 ownership">;
+/// Selector for a TagTypeKind value.
+def select_tag_type_kind : TextSubstitution<
+ "%select{struct|interface|union|class|enum}0">;
+
def err_static_data_member_not_allowed_in_anon_struct : Error<
- "static data member %0 not allowed in anonymous struct">;
+ "static data member %0 not allowed in anonymous "
+ "%sub{select_tag_type_kind}1">;
def ext_static_data_member_in_union : ExtWarn<
"static data member %0 in union is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_static_data_member_in_union : Warning<
@@ -8118,7 +8140,7 @@ def err_reference_to_local_in_enclosing_context : Error<
"%select{%3|block literal|lambda expression|context}2">;
def err_static_data_member_not_allowed_in_local_class : Error<
- "static data member %0 not allowed in local class %1">;
+ "static data member %0 not allowed in local %sub{select_tag_type_kind}2 %1">;
// C++ derived classes
def err_base_clause_on_union : Error<"unions cannot have base classes">;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 41c5119fe573..ff0bd939613c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4346,6 +4346,84 @@ void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) {
}
}
+namespace {
+struct NonCLikeKind {
+ enum {
+ None,
+ BaseClass,
+ DefaultMemberInit,
+ Lambda,
+ Friend,
+ OtherMember,
+ Invalid,
+ } Kind = None;
+ SourceRange Range;
+
+ explicit operator bool() { return Kind != None; }
+};
+}
+
+/// Determine whether a class is C-like, according to the rules of C++
+/// [dcl.typedef] for anonymous classes with typedef names for linkage.
+static NonCLikeKind getNonCLikeKindForAnonymousStruct(const CXXRecordDecl *RD) {
+ if (RD->isInvalidDecl())
+ return {NonCLikeKind::Invalid, {}};
+
+ // C++ [dcl.typedef]p9: [P1766R1]
+ // An unnamed class with a typedef name for linkage purposes shall not
+ //
+ // -- have any base classes
+ if (RD->getNumBases())
+ return {NonCLikeKind::BaseClass,
+ SourceRange(RD->bases_begin()->getBeginLoc(),
+ RD->bases_end()[-1].getEndLoc())};
+ bool Invalid = false;
+ for (Decl *D : RD->decls()) {
+ // Don't complain about things we already diagnosed.
+ if (D->isInvalidDecl()) {
+ Invalid = true;
+ continue;
+ }
+
+ // -- have any [...] default member initializers
+ if (auto *FD = dyn_cast<FieldDecl>(D)) {
+ if (FD->hasInClassInitializer()) {
+ auto *Init = FD->getInClassInitializer();
+ return {NonCLikeKind::DefaultMemberInit,
+ Init ? Init->getSourceRange() : D->getSourceRange()};
+ }
+ continue;
+ }
+
+ // FIXME: We don't allow friend declarations. This violates the wording of
+ // P1766, but not the intent.
+ if (isa<FriendDecl>(D))
+ return {NonCLikeKind::Friend, D->getSourceRange()};
+
+ // -- declare any members other than non-static data members, member
+ // enumerations, or member classes,
+ if (isa<StaticAssertDecl>(D) || isa<IndirectFieldDecl>(D) ||
+ isa<EnumDecl>(D))
+ continue;
+ auto *MemberRD = dyn_cast<CXXRecordDecl>(D);
+ if (!MemberRD)
+ return {NonCLikeKind::OtherMember, D->getSourceRange()};
+
+ // -- contain a lambda-expression,
+ if (MemberRD->isLambda())
+ return {NonCLikeKind::Lambda, MemberRD->getSourceRange()};
+
+ // and all member classes shall also satisfy these requirements
+ // (recursively).
+ if (MemberRD->isThisDeclarationADefinition()) {
+ if (auto Kind = getNonCLikeKindForAnonymousStruct(MemberRD))
+ return Kind;
+ }
+ }
+
+ return {Invalid ? NonCLikeKind::Invalid : NonCLikeKind::None, {}};
+}
+
void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec,
TypedefNameDecl *NewTD) {
if (TagFromDeclSpec->isInvalidDecl())
@@ -4366,27 +4444,51 @@ void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec,
return;
}
- // If we've already computed linkage for the anonymous tag, then
- // adding a typedef name for the anonymous decl can change that
- // linkage, which might be a serious problem. Diagnose this as
- // unsupported and ignore the typedef name. TODO: we should
- // pursue this as a language defect and establish a formal rule
- // for how to handle it.
- if (TagFromDeclSpec->hasLinkageBeenComputed()) {
- Diag(NewTD->getLocation(), diag::err_typedef_changes_linkage);
+ // C++ [dcl.typedef]p9: [P1766R1, applied as DR]
+ // An unnamed class with a typedef name for linkage purposes shall [be
+ // C-like].
+ //
+ // FIXME: Also diagnose if we've already computed the linkage. That ideally
+ // shouldn't happen, but there are constructs that the language rule doesn't
+ // disallow for which we can't reasonably avoid computing linkage early.
+ const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TagFromDeclSpec);
+ NonCLikeKind NonCLike = RD ? getNonCLikeKindForAnonymousStruct(RD)
+ : NonCLikeKind();
+ bool ChangesLinkage = TagFromDeclSpec->hasLinkageBeenComputed();
+ if (NonCLike || ChangesLinkage) {
+ if (NonCLike.Kind == NonCLikeKind::Invalid)
+ return;
- SourceLocation tagLoc = TagFromDeclSpec->getInnerLocStart();
- tagLoc = getLocForEndOfToken(tagLoc);
+ unsigned DiagID = diag::ext_non_c_like_anon_struct_in_typedef;
+ if (ChangesLinkage) {
+ // If the linkage changes, we can't accept this as an extension.
+ if (NonCLike.Kind == NonCLikeKind::None)
+ DiagID = diag::err_typedef_changes_linkage;
+ else
+ DiagID = diag::err_non_c_like_anon_struct_in_typedef;
+ }
- llvm::SmallString<40> textToInsert;
- textToInsert += ' ';
- textToInsert += NewTD->getIdentifier()->getName();
- Diag(tagLoc, diag::note_typedef_changes_linkage)
- << FixItHint::CreateInsertion(tagLoc, textToInsert);
- return;
+ SourceLocation FixitLoc =
+ getLocForEndOfToken(TagFromDeclSpec->getInnerLocStart());
+ llvm::SmallString<40> TextToInsert;
+ TextToInsert += ' ';
+ TextToInsert += NewTD->getIdentifier()->getName();
+
+ Diag(FixitLoc, DiagID)
+ << isa<TypeAliasDecl>(NewTD)
+ << FixItHint::CreateInsertion(FixitLoc, TextToInsert);
+ if (NonCLike.Kind != NonCLikeKind::None) {
+ Diag(NonCLike.Range.getBegin(), diag::note_non_c_like_anon_struct)
+ << NonCLike.Kind - 1 << NonCLike.Range;
+ }
+ Diag(NewTD->getLocation(), diag::note_typedef_for_linkage_here)
+ << NewTD << isa<TypeAliasDecl>(NewTD);
+
+ if (ChangesLinkage)
+ return;
}
- // Otherwise, set this is the anon-decl typedef for the tag.
+ // Otherwise, set this as the anon-decl typedef for the tag.
TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD);
}
@@ -4917,6 +5019,10 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
// define non-static data members. [Note: nested types and
// functions cannot be declared within an anonymous union. ]
for (auto *Mem : Record->decls()) {
+ // Ignore invalid declarations; we already diagnosed them.
+ if (Mem->isInvalidDecl())
+ continue;
+
if (auto *FD = dyn_cast<FieldDecl>(Mem)) {
// C++ [class.union]p3:
// An anonymous union shall not have private or protected
@@ -6757,28 +6863,33 @@ NamedDecl *Sema::ActOnVariableDeclarator(
if (SC == SC_Static && CurContext->isRecord()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
- if (RD->isLocalClass())
+ // C++ [class.static.data]p2:
+ // A static data member shall not be a direct member of an unnamed
+ // or local class
+ // FIXME: or of a (possibly indirectly) nested class thereof.
+ if (RD->isLocalClass()) {
Diag(D.getIdentifierLoc(),
diag::err_static_data_member_not_allowed_in_local_class)
- << Name << RD->getDeclName();
-
- // C++98 [class.union]p1: If a union contains a static data member,
- // the program is ill-formed. C++11 drops this restriction.
- if (RD->isUnion())
+ << Name << RD->getDeclName() << RD->getTagKind();
+ } else if (!RD->getDeclName()) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_static_data_member_not_allowed_in_anon_struct)
+ << Name << RD->getTagKind();
+ Invalid = true;
+ } else if (RD->isUnion()) {
+ // C++98 [class.union]p1: If a union contains a static data member,
+ // the program is ill-formed. C++11 drops this restriction.
Diag(D.getIdentifierLoc(),
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_static_data_member_in_union
: diag::ext_static_data_member_in_union) << Name;
- // We conservatively disallow static data members in anonymous structs.
- else if (!RD->getDeclName())
- Diag(D.getIdentifierLoc(),
- diag::err_static_data_member_not_allowed_in_anon_struct)
- << Name << RD->isUnion();
+ }
}
}
// Match up the template parameter lists with the scope specifier, then
// determine whether we have a template or a template specialization.
+ bool InvalidScope = false;
TemplateParams = MatchTemplateParametersToScopeSpecifier(
D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(),
D.getCXXScopeSpec(),
@@ -6786,7 +6897,8 @@ NamedDecl *Sema::ActOnVariableDeclarator(
? D.getName().TemplateId
: nullptr,
TemplateParamLists,
- /*never a friend*/ false, IsMemberSpecialization, Invalid);
+ /*never a friend*/ false, IsMemberSpecialization, InvalidScope);
+ Invalid |= InvalidScope;
if (TemplateParams) {
if (!TemplateParams->size() &&
diff --git a/clang/test/Analysis/inlining/eager-reclamation-path-notes.cpp b/clang/test/Analysis/inlining/eager-reclamation-path-notes.cpp
index 57c4a21fe8a6..c326150b0417 100644
--- a/clang/test/Analysis/inlining/eager-reclamation-path-notes.cpp
+++ b/clang/test/Analysis/inlining/eager-reclamation-path-notes.cpp
@@ -2,9 +2,9 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config graph-trim-interval=5 -analyzer-config suppress-null-return-paths=false %s -o %t.plist
// RUN: %normalize_plist <%t.plist |
diff -ub %S/Inputs/expected-plists/eager-reclamation-path-notes.cpp.plist -
-typedef struct {
+struct IntWrapper {
int getValue();
-} IntWrapper;
+};
IntWrapper *getNullWrapper() {
return 0;
diff --git a/clang/test/Analysis/padding_cpp.cpp b/clang/test/Analysis/padding_cpp.cpp
index ee49aea0c2be..f0e8beacda76 100644
--- a/clang/test/Analysis/padding_cpp.cpp
+++ b/clang/test/Analysis/padding_cpp.cpp
@@ -165,7 +165,7 @@ class Holder1 { // no-warning
TemplateSandwich<void *> t3;
};
-typedef struct { // expected-warning{{Excessive padding in 'TypedefSandwich2'}}
+typedef struct TypedefSandwich2 { // expected-warning{{Excessive padding in 'struct TypedefSandwich2'}}
char c1;
typedef struct { // expected-warning{{Excessive padding in 'TypedefSandwich2::NestedTypedef'}}
char c1;
diff --git a/clang/test/Analysis/padding_message.cpp b/clang/test/Analysis/padding_message.cpp
index 4c7e06108154..e8b9f4022a77 100644
--- a/clang/test/Analysis/padding_message.cpp
+++ b/clang/test/Analysis/padding_message.cpp
@@ -265,13 +265,13 @@ class LotsOfSpace {
};
// expected-warning at +7{{\
-Excessive padding in 'TypedefSandwich2' (6 padding bytes, where 2 is optimal). \
+Excessive padding in 'struct TypedefSandwich2' (6 padding bytes, where 2 is optimal). \
Optimal fields order: \
t, \
c1, \
c2, \
}}
-typedef struct {
+typedef struct TypedefSandwich2 {
char c1;
// expected-warning at +7{{\
Excessive padding in 'TypedefSandwich2::NestedTypedef' (6 padding bytes, where 2 is optimal). \
diff --git a/clang/test/CXX/class/class.local/p4.cpp b/clang/test/CXX/class/class.local/p4.cpp
index d7807440cc9c..2852d9627f42 100644
--- a/clang/test/CXX/class/class.local/p4.cpp
+++ b/clang/test/CXX/class/class.local/p4.cpp
@@ -2,9 +2,9 @@
void f() {
struct X {
- static int a; // expected-error {{static data member 'a' not allowed in local class 'X'}}
+ static int a; // expected-error {{static data member 'a' not allowed in local struct 'X'}}
int b;
-
+
static void f() { }
};
}
diff --git a/clang/test/CXX/class/class.union/p2-0x.cpp b/clang/test/CXX/class/class.union/p2-0x.cpp
index 5fb8a671e31b..50a8022ffcf0 100644
--- a/clang/test/CXX/class/class.union/p2-0x.cpp
+++ b/clang/test/CXX/class/class.union/p2-0x.cpp
@@ -37,12 +37,12 @@ union U3 {
struct S {
union {
- static const int n; // expected-error {{static members cannot be declared in an anonymous union}}
+ static const int n; // expected-error {{static data member 'n' not allowed in anonymous union}}
int a;
int b;
};
};
static union {
- static const int k; // expected-error {{static members cannot be declared in an anonymous union}}
+ static const int k; // expected-error {{static data member 'k' not allowed in anonymous union}}
int n;
};
diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp
index d37ece6cb882..35fd15f0cc64 100644
--- a/clang/test/CXX/drs/dr4xx.cpp
+++ b/clang/test/CXX/drs/dr4xx.cpp
@@ -82,6 +82,9 @@ namespace dr406 { // dr406: yes
typedef struct {
static int n; // expected-error {{static data member 'n' not allowed in anonymous struct}}
} A;
+ typedef union {
+ static int n; // expected-error {{static data member 'n' not allowed in anonymous union}}
+ } B;
}
namespace dr407 { // dr407: 3.8
diff --git a/clang/test/Modules/submodules-merge-defs.cpp b/clang/test/Modules/submodules-merge-defs.cpp
index 0f7637de5732..9e1ac6ceef28 100644
--- a/clang/test/Modules/submodules-merge-defs.cpp
+++ b/clang/test/Modules/submodules-merge-defs.cpp
@@ -10,6 +10,8 @@
#include "empty.h"
#ifdef EARLY_INDIRECT_INCLUDE
#include "indirect.h"
+// expected-warning at defs.h:28 3{{anonymous non-C-compatible type}}
+// expected-note at defs.h:28 6{{type is}}
#endif
A pre_a;
diff --git a/clang/test/OpenMP/target_map_codegen.cpp b/clang/test/OpenMP/target_map_codegen.cpp
index cd1b5e49174e..b9766e82ce03 100644
--- a/clang/test/OpenMP/target_map_codegen.cpp
+++ b/clang/test/OpenMP/target_map_codegen.cpp
@@ -5165,7 +5165,7 @@ typedef struct {
int *ptrBase1;
} Base;
-typedef struct : public Base {
+typedef struct StructWithPtrTag : public Base {
int *ptr;
int *ptr2;
int val;
diff --git a/clang/test/SemaCXX/anonymous-struct.cpp b/clang/test/SemaCXX/anonymous-struct.cpp
index 42770030d2fa..017c867c95db 100644
--- a/clang/test/SemaCXX/anonymous-struct.cpp
+++ b/clang/test/SemaCXX/anonymous-struct.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
struct S {
S();
@@ -27,15 +28,108 @@ struct E {
};
template <class T> void foo(T);
-typedef struct { // expected-note {{use a tag name here to establish linkage prior to definition}}
+typedef struct { // expected-error {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration after its linkage was computed; add a tag name here to establish linkage prior to definition}}
#if __cplusplus <= 199711L
// expected-note at -2 {{declared here}}
#endif
- void test() {
+ void test() { // expected-note {{type is not C-compatible due to this member declaration}}
foo(this);
#if __cplusplus <= 199711L
// expected-warning at -2 {{template argument uses unnamed type}}
#endif
}
-} A; // expected-error {{unsupported: typedef changes linkage of anonymous type, but linkage was already computed}}
+} A; // expected-note {{type is given name 'A' for linkage purposes by this typedef declaration}}
+
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ int x = 0; // expected-note {{type is not C-compatible due to this default member initializer}} expected-warning 0-1{{extension}}
+} B; // expected-note {{type is given name 'B' for linkage purposes by this typedef declaration}}
+
+typedef struct // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+: B { // expected-note {{type is not C-compatible due to this base class}}
+} C; // expected-note {{type is given name 'C' for linkage purposes by this typedef declaration}}
+
+#if __cplusplus > 201703L
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ static_assert([]{ return true; }()); // expected-note {{type is not C-compatible due to this lambda expression}}
+} Lambda1; // expected-note {{type is given name 'Lambda1' for linkage purposes by this typedef declaration}}
+
+template<int> struct X {};
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ X<[]{ return 0; }()> x; // expected-note {{type is not C-compatible due to this lambda expression}}
+ // FIXME: expected-error at -1 {{lambda expression cannot appear}}
+} Lambda2; // expected-note {{type is given name 'Lambda2' for linkage purposes by this typedef declaration}}
+
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ enum E {
+ a = []{ return 1; }() // expected-note {{type is not C-compatible due to this lambda expression}}
+ };
+} Lambda3; // expected-note {{type is given name 'Lambda3' for linkage purposes by this typedef declaration}}
+#endif
+
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ template<int> void f() {} // expected-note {{type is not C-compatible due to this member declaration}}
+} Template; // expected-note {{type is given name 'Template' for linkage purposes by this typedef declaration}}
+
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ struct U {
+ void f(); // expected-note {{type is not C-compatible due to this member declaration}}
+ };
+} Nested; // expected-note {{type is given name 'Nested' for linkage purposes by this typedef declaration}}
+
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ friend void f() {} // expected-note {{type is not C-compatible due to this friend declaration}}
+} Friend; // expected-note {{type is given name 'Friend' for linkage purposes by this typedef declaration}}
+
+typedef struct { // expected-warning {{anonymous non-C-compatible type given name for linkage purposes by typedef declaration; add a tag name here}}
+ template<typename T> friend void f() {} // expected-note {{type is not C-compatible due to this friend declaration}}
+} FriendTemplate; // expected-note {{type is given name 'FriendTemplate' for linkage purposes by this typedef declaration}}
+
+// Check that we don't diagnose the permitted cases:
+typedef struct {
+ // (non-members)
+ _Static_assert(true, "");
+ int : 0;
+ /*empty-declaration*/;
+
+ // non-static data members
+ int a;
+ // member enumerations
+ enum E { x, y, z };
+ // member classes
+ struct S {};
+
+ // recursively
+ struct T { int a; };
+} OK;
+
+// There are still some known permitted cases that require an early linkage
+// computation. Ensure we diagnose those too.
+namespace ValidButUnsupported {
+#if __cplusplus >= 201402L
+ template<typename T> auto compute_linkage() {
+ static int n;
+ return &n;
+ }
+
+ typedef struct { // expected-error {{unsupported: anonymous type given name for linkage purposes by typedef declaration after its linkage was computed; add a tag name here to establish linkage}}
+ struct X {};
+ decltype(compute_linkage<X>()) a;
+ } A; // expected-note {{by this typedef declaration}}
+#endif
+
+ // This fails in some language modes but not others.
+ template<typename T> struct Y {
+ static const int value = 10;
+ };
+ typedef struct { // expected-error 0-1{{unsupported}}
+ enum X {};
+ int arr[Y<X>::value];
+ } B; // expected-note 0-1{{by this typedef}}
+
+ template<typename T> void f() {}
+ typedef struct { // expected-error {{unsupported}}
+ enum X {};
+ int arr[&f<X> ? 1 : 2];
+ } C; // expected-note {{by this typedef}}
+}
diff --git a/clang/test/SemaCXX/linkage.cpp b/clang/test/SemaCXX/linkage.cpp
index aa595948c696..6b5f2f75fb23 100644
--- a/clang/test/SemaCXX/linkage.cpp
+++ b/clang/test/SemaCXX/linkage.cpp
@@ -3,7 +3,7 @@
// compared against the earlier cached value. If we had a way of
// testing linkage directly in Sema, that would be better.
-// RUN: %clang_cc1 -Werror -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -Werror -Wno-non-c-typedef-for-linkage -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
// CHECK: @_ZZN5test61A3fooEvE3bar = linkonce_odr global i32 0, align 4
diff --git a/clang/test/SemaCXX/linkage2.cpp b/clang/test/SemaCXX/linkage2.cpp
index 3cc9f61f0882..6fd0081450bf 100644
--- a/clang/test/SemaCXX/linkage2.cpp
+++ b/clang/test/SemaCXX/linkage2.cpp
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=gnu++11 %s
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions -Wno-local-type-template-args %s -std=gnu++98
-// RUN: %clang_cc1 -fsyntax-only -verify -Wno-c++11-extensions -Wno-local-type-template-args -fmodules %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-non-c-typedef-for-linkage -std=gnu++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-non-c-typedef-for-linkage -Wno-c++11-extensions -Wno-local-type-template-args %s -std=gnu++98
+// RUN: %clang_cc1 -fsyntax-only -verify -Wno-non-c-typedef-for-linkage -Wno-c++11-extensions -Wno-local-type-template-args -fmodules %s
namespace test1 {
int x; // expected-note {{previous definition is here}}
@@ -245,7 +245,8 @@ namespace typedef_name_for_linkage {
void f() { struct Inner {}; Use<Inner> ui; }
} F;
#if __cplusplus < 201103L
- // expected-error at -2 {{unsupported: typedef changes linkage of anonymous type, but linkage was already computed}}
- // expected-note at -5 {{use a tag name here}}
+ // expected-error at -4 {{given name for linkage purposes by typedef declaration after its linkage was computed}}
+ // expected-note at -4 {{due to this member}}
+ // expected-note at -4 {{by this typedef}}
#endif
}
diff --git a/clang/test/SemaCXX/undefined-internal.cpp b/clang/test/SemaCXX/undefined-internal.cpp
index 60fa202384de..abbd0921fd7b 100644
--- a/clang/test/SemaCXX/undefined-internal.cpp
+++ b/clang/test/SemaCXX/undefined-internal.cpp
@@ -206,12 +206,12 @@ namespace OverloadUse {
}
namespace test7 {
- typedef struct {
- void bar();
+ typedef struct { // expected-warning {{add a tag name}}
+ void bar(); // expected-note {{this member}}
void foo() {
bar();
}
- } A;
+ } A; // expected-note {{this typedef}}
}
namespace test8 {
diff --git a/clang/test/SemaCXX/warn-unused-filescoped.cpp b/clang/test/SemaCXX/warn-unused-filescoped.cpp
index e052ecb1af99..7ea398feb2b1 100644
--- a/clang/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/clang/test/SemaCXX/warn-unused-filescoped.cpp
@@ -164,9 +164,9 @@ namespace unused {
}
namespace test6 {
- typedef struct {
- void bar();
- } A;
+ typedef struct { // expected-warning {{add a tag name}}
+ void bar(); // expected-note {{}}
+ } A; // expected-note {{}}
typedef struct {
void bar(); // expected-warning {{unused member function 'bar'}}
diff --git a/clang/test/SemaCXX/warn-unused-local-typedef.cpp b/clang/test/SemaCXX/warn-unused-local-typedef.cpp
index a9406531d2d7..7e893ba506a5 100644
--- a/clang/test/SemaCXX/warn-unused-local-typedef.cpp
+++ b/clang/test/SemaCXX/warn-unused-local-typedef.cpp
@@ -108,13 +108,13 @@ void template_fun_user() {
}
void typedef_in_nested_name() {
- typedef struct {
- typedef int Foo;
- } A;
+ typedef struct { // expected-warning {{add a tag name}}
+ typedef int Foo; // expected-note {{}}
+ } A; // expected-note {{}}
A::Foo adsf;
- using A2 = struct {
- typedef int Foo;
+ using A2 = struct { // expected-warning {{add a tag name}} expected-note {{this alias declaration}}
+ typedef int Foo; // expected-note {{}}
};
A2::Foo adsf2;
}
diff --git a/clang/test/SemaTemplate/instantiate-function-2.cpp b/clang/test/SemaTemplate/instantiate-function-2.cpp
index ffdb4c914457..40d4a19cd081 100644
--- a/clang/test/SemaTemplate/instantiate-function-2.cpp
+++ b/clang/test/SemaTemplate/instantiate-function-2.cpp
@@ -49,11 +49,11 @@ namespace PR9654 {
namespace AliasTagDef {
template<typename T>
T f() {
- using S = struct {
+ using S = struct { // expected-warning {{add a tag name}} expected-note {{}}
#if __cplusplus <= 199711L
// expected-warning at -2 {{alias declarations are a C++11 extension}}
#endif
- T g() {
+ T g() { // expected-note {{}}
return T();
}
};
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 606b8c956f16..171adbbae0eb 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1091,7 +1091,7 @@ <h2 id="cxx20">C++2a implementation status</h2>
</tr>
<tr> <!-- from Cologne -->
<td><a href="https://wg21.link/p1766r1">P1766R1</a> (<a href="#dr">DR</a>)</td>
- <td rowspan="3" class="none" align="center">No</td>
+ <td rowspan="3" class="unreleased" align="center">Clang 11</td>
</tr>
<tr>
<td><a href="https://wg21.link/p1811r0">P1811R0</a></td>
More information about the cfe-commits
mailing list