Skip to content

Commit d33f6f4

Browse files
committed
Merge from 'main' to 'sycl-web' (33 commits)
CONFLICT (content): Merge conflict in llvm/lib/IR/BasicBlock.cpp
2 parents 1dbb9fd + fd3a0c1 commit d33f6f4

File tree

148 files changed

+6527
-2927
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

148 files changed

+6527
-2927
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ Improvements to Clang's diagnostics
159159
- The ``-Wshorten-64-to-32`` diagnostic is now grouped under ``-Wimplicit-int-conversion`` instead
160160
of ``-Wconversion``. Fixes `#69444 <https://github.com/llvm/llvm-project/issues/69444>`_.
161161

162+
- Clang now diagnoses friend declarations with an ``enum`` elaborated-type-specifier in language modes after C++98.
163+
162164
Improvements to Clang's time-trace
163165
----------------------------------
164166

clang/include/clang/Basic/Builtins.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
#include "llvm/ADT/StringRef.h"
2121
#include <cstring>
2222

23+
// VC++ defines 'alloca' as an object-like macro, which interferes with our
24+
// builtins.
25+
#undef alloca
26+
2327
namespace clang {
2428
class TargetInfo;
2529
class IdentifierTable;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,10 +1680,10 @@ def err_inline_namespace_std : Error<
16801680
def err_unexpected_friend : Error<
16811681
"friends can only be classes or functions">;
16821682
def ext_enum_friend : ExtWarn<
1683-
"befriending enumeration type %0 is a C++11 extension">, InGroup<CXX11>;
1684-
def warn_cxx98_compat_enum_friend : Warning<
1685-
"befriending enumeration type %0 is incompatible with C++98">,
1686-
InGroup<CXX98Compat>, DefaultIgnore;
1683+
"elaborated enum specifier cannot be declared as a friend">,
1684+
InGroup<DiagGroup<"friend-enum">>;
1685+
def note_enum_friend : Note<
1686+
"remove 'enum%select{| struct| class}0' to befriend an enum">;
16871687
def ext_nonclass_type_friend : ExtWarn<
16881688
"non-class friend type %0 is a C++11 extension">, InGroup<CXX11>;
16891689
def warn_cxx98_compat_nonclass_type_friend : Warning<

clang/include/clang/Sema/DeclSpec.h

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,7 @@ class DeclSpec {
346346
// FIXME: Attributes should be included here.
347347
};
348348

349-
enum FriendSpecified : bool {
350-
No,
351-
Yes,
352-
};
349+
enum FriendSpecified : bool { No, Yes };
353350

354351
private:
355352
// storage-class-specifier
@@ -400,7 +397,7 @@ class DeclSpec {
400397

401398
// friend-specifier
402399
LLVM_PREFERRED_TYPE(bool)
403-
unsigned Friend_specified : 1;
400+
unsigned FriendSpecifiedFirst : 1;
404401

405402
// constexpr-specifier
406403
LLVM_PREFERRED_TYPE(ConstexprSpecKind)
@@ -491,7 +488,7 @@ class DeclSpec {
491488
TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
492489
TypeQualifiers(TQ_unspecified), FS_inline_specified(false),
493490
FS_forceinline_specified(false), FS_virtual_specified(false),
494-
FS_noreturn_specified(false), Friend_specified(false),
491+
FS_noreturn_specified(false), FriendSpecifiedFirst(false),
495492
ConstexprSpecifier(
496493
static_cast<unsigned>(ConstexprSpecKind::Unspecified)),
497494
Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {}
@@ -818,9 +815,11 @@ class DeclSpec {
818815
const char *&PrevSpec, unsigned &DiagID);
819816

820817
FriendSpecified isFriendSpecified() const {
821-
return static_cast<FriendSpecified>(Friend_specified);
818+
return static_cast<FriendSpecified>(FriendLoc.isValid());
822819
}
823820

821+
bool isFriendSpecifiedFirst() const { return FriendSpecifiedFirst; }
822+
824823
SourceLocation getFriendSpecLoc() const { return FriendLoc; }
825824

826825
bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); }

clang/include/clang/Sema/Sema.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8318,9 +8318,6 @@ class Sema final {
83188318
SourceLocation RParenLoc, bool Failed);
83198319
void DiagnoseStaticAssertDetails(const Expr *E);
83208320

8321-
FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart,
8322-
SourceLocation FriendLoc,
8323-
TypeSourceInfo *TSInfo);
83248321
Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
83258322
MultiTemplateParamsArg TemplateParams);
83268323
NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D,

clang/lib/Parse/ParseTentative.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ bool Parser::isCXXDeclarationStatement(
7979
getCurScope(), *II, Tok.getLocation(), SS, /*Template=*/nullptr);
8080
if (Actions.isCurrentClassName(*II, getCurScope(), &SS) ||
8181
isDeductionGuide) {
82-
if (isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(),
83-
isDeductionGuide,
84-
DeclSpec::FriendSpecified::No))
82+
if (isConstructorDeclarator(
83+
/*Unqualified=*/SS.isEmpty(), isDeductionGuide,
84+
/*IsFriend=*/DeclSpec::FriendSpecified::No))
8585
return true;
8686
} else if (SS.isNotEmpty()) {
8787
// If the scope is not empty, it could alternatively be something like

clang/lib/Sema/DeclSpec.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,18 +1102,13 @@ bool DeclSpec::setFunctionSpecNoreturn(SourceLocation Loc,
11021102

11031103
bool DeclSpec::SetFriendSpec(SourceLocation Loc, const char *&PrevSpec,
11041104
unsigned &DiagID) {
1105-
if (Friend_specified) {
1105+
if (isFriendSpecified()) {
11061106
PrevSpec = "friend";
1107-
// Keep the later location, so that we can later diagnose ill-formed
1108-
// declarations like 'friend class X friend;'. Per [class.friend]p3,
1109-
// 'friend' must be the first token in a friend declaration that is
1110-
// not a function declaration.
1111-
FriendLoc = Loc;
11121107
DiagID = diag::warn_duplicate_declspec;
11131108
return true;
11141109
}
11151110

1116-
Friend_specified = true;
1111+
FriendSpecifiedFirst = isEmpty();
11171112
FriendLoc = Loc;
11181113
return false;
11191114
}

clang/lib/Sema/SemaDecl.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17379,6 +17379,26 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
1737917379
return true;
1738017380
}
1738117381

17382+
if (TUK == TUK_Friend && Kind == TagTypeKind::Enum) {
17383+
// C++23 [dcl.type.elab]p4:
17384+
// If an elaborated-type-specifier appears with the friend specifier as
17385+
// an entire member-declaration, the member-declaration shall have one
17386+
// of the following forms:
17387+
// friend class-key nested-name-specifier(opt) identifier ;
17388+
// friend class-key simple-template-id ;
17389+
// friend class-key nested-name-specifier template(opt)
17390+
// simple-template-id ;
17391+
//
17392+
// Since enum is not a class-key, so declarations like "friend enum E;"
17393+
// are ill-formed. Although CWG2363 reaffirms that such declarations are
17394+
// invalid, most implementations accept so we issue a pedantic warning.
17395+
Diag(KWLoc, diag::ext_enum_friend) << FixItHint::CreateRemoval(
17396+
ScopedEnum ? SourceRange(KWLoc, ScopedEnumKWLoc) : KWLoc);
17397+
assert(ScopedEnum || !ScopedEnumUsesClassTag);
17398+
Diag(KWLoc, diag::note_enum_friend)
17399+
<< (ScopedEnum + ScopedEnumUsesClassTag);
17400+
}
17401+
1738217402
// Figure out the underlying type if this a enum declaration. We need to do
1738317403
// this early, because it's needed to detect if this is an incompatible
1738417404
// redeclaration.

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 38 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -17572,79 +17572,6 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc,
1757217572
return Decl;
1757317573
}
1757417574

17575-
/// Perform semantic analysis of the given friend type declaration.
17576-
///
17577-
/// \returns A friend declaration that.
17578-
FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart,
17579-
SourceLocation FriendLoc,
17580-
TypeSourceInfo *TSInfo) {
17581-
assert(TSInfo && "NULL TypeSourceInfo for friend type declaration");
17582-
17583-
QualType T = TSInfo->getType();
17584-
SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange();
17585-
17586-
// C++03 [class.friend]p2:
17587-
// An elaborated-type-specifier shall be used in a friend declaration
17588-
// for a class.*
17589-
//
17590-
// * The class-key of the elaborated-type-specifier is required.
17591-
if (!CodeSynthesisContexts.empty()) {
17592-
// Do not complain about the form of friend template types during any kind
17593-
// of code synthesis. For template instantiation, we will have complained
17594-
// when the template was defined.
17595-
} else {
17596-
if (!T->isElaboratedTypeSpecifier()) {
17597-
// If we evaluated the type to a record type, suggest putting
17598-
// a tag in front.
17599-
if (const RecordType *RT = T->getAs<RecordType>()) {
17600-
RecordDecl *RD = RT->getDecl();
17601-
17602-
SmallString<16> InsertionText(" ");
17603-
InsertionText += RD->getKindName();
17604-
17605-
Diag(TypeRange.getBegin(),
17606-
getLangOpts().CPlusPlus11 ?
17607-
diag::warn_cxx98_compat_unelaborated_friend_type :
17608-
diag::ext_unelaborated_friend_type)
17609-
<< (unsigned) RD->getTagKind()
17610-
<< T
17611-
<< FixItHint::CreateInsertion(getLocForEndOfToken(FriendLoc),
17612-
InsertionText);
17613-
} else {
17614-
Diag(FriendLoc,
17615-
getLangOpts().CPlusPlus11 ?
17616-
diag::warn_cxx98_compat_nonclass_type_friend :
17617-
diag::ext_nonclass_type_friend)
17618-
<< T
17619-
<< TypeRange;
17620-
}
17621-
} else if (T->getAs<EnumType>()) {
17622-
Diag(FriendLoc,
17623-
getLangOpts().CPlusPlus11 ?
17624-
diag::warn_cxx98_compat_enum_friend :
17625-
diag::ext_enum_friend)
17626-
<< T
17627-
<< TypeRange;
17628-
}
17629-
17630-
// C++11 [class.friend]p3:
17631-
// A friend declaration that does not declare a function shall have one
17632-
// of the following forms:
17633-
// friend elaborated-type-specifier ;
17634-
// friend simple-type-specifier ;
17635-
// friend typename-specifier ;
17636-
if (getLangOpts().CPlusPlus11 && LocStart != FriendLoc)
17637-
Diag(FriendLoc, diag::err_friend_not_first_in_declaration) << T;
17638-
}
17639-
17640-
// If the type specifier in a friend declaration designates a (possibly
17641-
// cv-qualified) class type, that class is declared as a friend; otherwise,
17642-
// the friend declaration is ignored.
17643-
return FriendDecl::Create(Context, CurContext,
17644-
TSInfo->getTypeLoc().getBeginLoc(), TSInfo,
17645-
FriendLoc);
17646-
}
17647-
1764817575
/// Handle a friend tag declaration where the scope specifier was
1764917576
/// templated.
1765017577
DeclResult Sema::ActOnTemplatedFriendTag(
@@ -17782,6 +17709,7 @@ DeclResult Sema::ActOnTemplatedFriendTag(
1778217709
Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
1778317710
MultiTemplateParamsArg TempParams) {
1778417711
SourceLocation Loc = DS.getBeginLoc();
17712+
SourceLocation FriendLoc = DS.getFriendSpecLoc();
1778517713

1778617714
assert(DS.isFriendSpecified());
1778717715
assert(DS.getStorageClassSpec() == DeclSpec::SCS_unspecified);
@@ -17793,9 +17721,10 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
1779317721
// friend simple-type-specifier ;
1779417722
// friend typename-specifier ;
1779517723
//
17796-
// Any declaration with a type qualifier does not have that form. (It's
17797-
// legal to specify a qualified type as a friend, you just can't write the
17798-
// keywords.)
17724+
// If the friend keyword isn't first, or if the declarations has any type
17725+
// qualifiers, then the declaration doesn't have that form.
17726+
if (getLangOpts().CPlusPlus11 && !DS.isFriendSpecifiedFirst())
17727+
Diag(FriendLoc, diag::err_friend_not_first_in_declaration);
1779917728
if (DS.getTypeQualifiers()) {
1780017729
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
1780117730
Diag(DS.getConstSpecLoc(), diag::err_friend_decl_spec) << "const";
@@ -17822,24 +17751,35 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
1782217751
if (DiagnoseUnexpandedParameterPack(Loc, TSI, UPPC_FriendDeclaration))
1782317752
return nullptr;
1782417753

17825-
// This is definitely an error in C++98. It's probably meant to
17826-
// be forbidden in C++0x, too, but the specification is just
17827-
// poorly written.
17828-
//
17829-
// The problem is with declarations like the following:
17830-
// template <T> friend A<T>::foo;
17831-
// where deciding whether a class C is a friend or not now hinges
17832-
// on whether there exists an instantiation of A that causes
17833-
// 'foo' to equal C. There are restrictions on class-heads
17834-
// (which we declare (by fiat) elaborated friend declarations to
17835-
// be) that makes this tractable.
17836-
//
17837-
// FIXME: handle "template <> friend class A<T>;", which
17838-
// is possibly well-formed? Who even knows?
17839-
if (TempParams.size() && !T->isElaboratedTypeSpecifier()) {
17840-
Diag(Loc, diag::err_tagless_friend_type_template)
17841-
<< DS.getSourceRange();
17842-
return nullptr;
17754+
if (!T->isElaboratedTypeSpecifier()) {
17755+
if (TempParams.size()) {
17756+
// C++23 [dcl.pre]p5:
17757+
// In a simple-declaration, the optional init-declarator-list can be
17758+
// omitted only when declaring a class or enumeration, that is, when
17759+
// the decl-specifier-seq contains either a class-specifier, an
17760+
// elaborated-type-specifier with a class-key, or an enum-specifier.
17761+
//
17762+
// The declaration of a template-declaration or explicit-specialization
17763+
// is never a member-declaration, so this must be a simple-declaration
17764+
// with no init-declarator-list. Therefore, this is ill-formed.
17765+
Diag(Loc, diag::err_tagless_friend_type_template) << DS.getSourceRange();
17766+
return nullptr;
17767+
} else if (const RecordDecl *RD = T->getAsRecordDecl()) {
17768+
SmallString<16> InsertionText(" ");
17769+
InsertionText += RD->getKindName();
17770+
17771+
Diag(Loc, getLangOpts().CPlusPlus11
17772+
? diag::warn_cxx98_compat_unelaborated_friend_type
17773+
: diag::ext_unelaborated_friend_type)
17774+
<< (unsigned)RD->getTagKind() << T
17775+
<< FixItHint::CreateInsertion(getLocForEndOfToken(FriendLoc),
17776+
InsertionText);
17777+
} else {
17778+
Diag(FriendLoc, getLangOpts().CPlusPlus11
17779+
? diag::warn_cxx98_compat_nonclass_type_friend
17780+
: diag::ext_nonclass_type_friend)
17781+
<< T << DS.getSourceRange();
17782+
}
1784317783
}
1784417784

1784517785
// C++98 [class.friend]p1: A friend of a class is a function
@@ -17855,12 +17795,11 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
1785517795

1785617796
Decl *D;
1785717797
if (!TempParams.empty())
17858-
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
17859-
TempParams,
17860-
TSI,
17861-
DS.getFriendSpecLoc());
17798+
D = FriendTemplateDecl::Create(Context, CurContext, Loc, TempParams, TSI,
17799+
FriendLoc);
1786217800
else
17863-
D = CheckFriendTypeDecl(Loc, DS.getFriendSpecLoc(), TSI);
17801+
D = FriendDecl::Create(Context, CurContext, TSI->getTypeLoc().getBeginLoc(),
17802+
TSI, FriendLoc);
1786417803

1786517804
if (!D)
1786617805
return nullptr;

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,11 +1924,8 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) {
19241924
if (!InstTy)
19251925
return nullptr;
19261926

1927-
FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getBeginLoc(),
1928-
D->getFriendLoc(), InstTy);
1929-
if (!FD)
1930-
return nullptr;
1931-
1927+
FriendDecl *FD = FriendDecl::Create(
1928+
SemaRef.Context, Owner, D->getLocation(), InstTy, D->getFriendLoc());
19321929
FD->setAccess(AS_public);
19331930
FD->setUnsupportedFriend(D->isUnsupportedFriend());
19341931
Owner->addDecl(FD);

clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ class A1 {
1616
friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
1717

1818
friend enum A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
19-
friend enum E;
20-
#if __cplusplus <= 199711L // C++03 or earlier modes
21-
// expected-warning@-2 {{befriending enumeration type 'enum E' is a C++11 extension}}
22-
#endif
19+
// expected-warning@-1 {{cannot be declared as a friend}}
20+
// expected-note@-2 {{remove 'enum' to befriend an enum}}
21+
friend enum E; // expected-warning {{cannot be declared as a friend}}
22+
// expected-note@-1 {{remove 'enum' to befriend an enum}}
2323
};
2424

2525
template <class T> struct B { // expected-note {{previous use is here}}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %clang_cc1 -verify %s -std=c++11 -pedantic-errors
2+
3+
enum class E;
4+
5+
template<typename T>
6+
struct A {
7+
enum class F;
8+
};
9+
10+
struct B {
11+
template<typename T>
12+
friend enum A<T>::F; // expected-error {{elaborated enum specifier cannot be declared as a friend}}
13+
// expected-note@-1 {{remove 'enum' to befriend an enum}}
14+
15+
// FIXME: Per [temp.expl.spec]p19, a friend declaration cannot be an explicit specialization
16+
template<>
17+
friend enum A<int>::F; // expected-error {{elaborated enum specifier cannot be declared as a friend}}
18+
// expected-note@-1 {{remove 'enum' to befriend an enum}}
19+
20+
enum class G;
21+
22+
friend enum E; // expected-error {{elaborated enum specifier cannot be declared as a friend}}
23+
// expected-note@-1 {{remove 'enum' to befriend an enum}}
24+
};
25+
26+
template<typename T>
27+
struct C {
28+
friend enum T::G; // expected-error {{elaborated enum specifier cannot be declared as a friend}}
29+
// expected-note@-1 {{remove 'enum' to befriend an enum}}
30+
friend enum A<T>::G; // expected-error {{elaborated enum specifier cannot be declared as a friend}}
31+
// expected-note@-1 {{remove 'enum' to befriend an enum}}
32+
};
33+
34+
struct D {
35+
friend enum B::G; // expected-error {{elaborated enum specifier cannot be declared as a friend}}
36+
// expected-note@-1 {{remove 'enum' to befriend an enum}}
37+
friend enum class B::G; // expected-error {{elaborated enum specifier cannot be declared as a friend}}
38+
// expected-note@-1 {{remove 'enum class' to befriend an enum}}
39+
// expected-error@-2 {{reference to enumeration must use 'enum' not 'enum class'}}
40+
};

0 commit comments

Comments
 (0)