Skip to content

Commit 964a046

Browse files
macurtis-amdronlieb
authored andcommitted
[clang] Apply missing changes from several Sema-related commits
cherry-picked: 8009bbe sdkrystian@gmail.com Tue Apr 30 14:25:09 2024 -0400 Reapply "[Clang][Sema] Diagnose class member access expressions naming non-existent members of the current instantiation prior to instantiation in the absence of dependent base classes (llvm#84050)" (llvm#90152) 3191e0b sdkrystian@gmail.com Fri May 3 17:07:52 2024 -0400 [Clang][Sema] Fix template name lookup for operator= (llvm#90999) 62b5b61 sdkrystian@gmail.com Wed May 8 20:49:59 2024 -0400 [Clang][Sema] Fix lookup of dependent operator= outside of complete-class contexts (llvm#91498) 75ebcbf sdkrystian@gmail.com Thu May 9 16:34:40 2024 -0400 [Clang][Sema] Revert changes to operator= lookup in templated classes from llvm#91498, llvm#90999, and llvm#90152 (llvm#91620) 596a9c1 sdkrystian@gmail.com Mon May 13 12:24:46 2024 -0400 [Clang][Sema] Fix bug where operator-> typo corrects in the current instantiation (llvm#91972) fd87d76 sdkrystian@gmail.com Mon May 20 13:55:01 2024 -0400 [Clang][Sema] Don't build CXXDependentScopeMemberExprs for potentially implicit class member access expressions (llvm#92318) e75b58c sdkrystian@gmail.com Mon May 20 14:50:58 2024 -0400 [Clang][Sema] Do not add implicit 'const' when matching constexpr function template explicit specializations after C++14 (llvm#92449) bae2c54 serebrennikov.vladislav@gmail.com Mon Jul 1 20:55:57 2024 +0300 [clang][NFC] Move documentation of `Sema` functions into `Sema.h` e6d305e dzenis@richard.lv Mon Sep 4 16:54:42 2023 +0200 Add support of Windows Trace Logging macros Change-Id: I521b2ebabd7eb9a0df78c577992bfd8508ba44fd
1 parent 0281651 commit 964a046

File tree

12 files changed

+87
-107
lines changed

12 files changed

+87
-107
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,8 @@ Bug Fixes in This Version
465465
- Fixed a crash when diagnosing format strings and encountering an empty
466466
delimited escape sequence (e.g., ``"\o{}"``). #GH102218
467467
- Fixed a crash using ``__array_rank`` on 64-bit targets. (#GH113044).
468+
- Support MSVC predefined macro expressions in constant expressions and in
469+
local structs.
468470
- The warning emitted for an unsupported register variable type now points to
469471
the unsupported type instead of the ``register`` keyword (#GH109776).
470472

@@ -542,6 +544,9 @@ Bug Fixes to C++ Support
542544
- Fixed an assertion failure in debug mode, and potential crashes in release mode, when
543545
diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter.
544546
- Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326)
547+
- Clang no longer treats ``constexpr`` class scope function template specializations of non-static members
548+
as implicitly ``const`` in language modes after C++11.
549+
- Mangle friend function templates with a constraint that depends on a template parameter from an enclosing template as members of the enclosing class. (#GH110247)
545550
- Fixed an issue deducing non-type template arguments of reference type. (#GH73460)
546551
- Fixed an issue in constraint evaluation, where type constraints on the lambda expression
547552
containing outer unexpanded parameters were not correctly expanded. (#GH101754)

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3980,10 +3980,6 @@ class Sema final : public SemaBase {
39803980
void ActOnReenterFunctionContext(Scope *S, Decl *D);
39813981
void ActOnExitFunctionContext();
39823982

3983-
/// getCurLocalScopeDecl - Return the Decl for either of:
3984-
/// block, lambda, captured statement, function, or nullptr.
3985-
Decl *getCurLocalScopeDecl();
3986-
39873983
/// Add this decl to the scope shadowed decl chains.
39883984
void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true);
39893985

@@ -6731,6 +6727,10 @@ class Sema final : public SemaBase {
67316727
bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R,
67326728
bool HasTrailingLParen);
67336729

6730+
/// BuildQualifiedDeclarationNameExpr - Build a C++ qualified
6731+
/// declaration name, generally during template instantiation.
6732+
/// There's a large number of things which don't need to be done along
6733+
/// this path.
67346734
ExprResult BuildQualifiedDeclarationNameExpr(
67356735
CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
67366736
bool IsAddressOfOperand, TypeSourceInfo **RecoveryTSI = nullptr);

clang/lib/Sema/Sema.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,18 +1578,6 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() const {
15781578
return nullptr;
15791579
}
15801580

1581-
Decl *Sema::getCurLocalScopeDecl() {
1582-
if (const BlockScopeInfo *BSI = getCurBlock())
1583-
return BSI->TheDecl;
1584-
if (const LambdaScopeInfo *LSI = getCurLambda())
1585-
return LSI->CallOperator;
1586-
if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion())
1587-
return CSI->TheCapturedDecl;
1588-
if (NamedDecl *ND = getCurFunctionOrMethodDecl())
1589-
return ND;
1590-
return nullptr;
1591-
}
1592-
15931581
LangAS Sema::getDefaultCXXMethodAddrSpace() const {
15941582
if (getLangOpts().OpenCL)
15951583
return getASTContext().getDefaultOpenCLPointeeAddrSpace();

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,10 +2629,6 @@ bool Sema::isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS) {
26292629
return false;
26302630
}
26312631

2632-
/// Check the validity of a C++ base class specifier.
2633-
///
2634-
/// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics
2635-
/// and returns NULL otherwise.
26362632
CXXBaseSpecifier *Sema::CheckBaseSpecifier(CXXRecordDecl *Class,
26372633
SourceRange SpecifierRange,
26382634
bool Virtual, AccessSpecifier Access,

clang/lib/Sema/SemaExpr.cpp

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,6 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
663663

664664
// We don't want to throw lvalue-to-rvalue casts on top of
665665
// expressions of certain types in C++.
666-
667666
if (getLangOpts().CPlusPlus) {
668667
if (T == Context.OverloadTy || T->isRecordType() ||
669668
(T->isDependentType() && !T->isAnyPointerType() &&
@@ -1895,15 +1894,6 @@ ExprResult Sema::CreateGenericSelectionExpr(
18951894
ContainsUnexpandedParameterPack, ResultIndex);
18961895
}
18971896

1898-
/// getPredefinedExprDecl - Returns Decl of a given DeclContext that can be used
1899-
/// to determine the value of a PredefinedExpr. This can be either a
1900-
/// block, lambda, captured statement, function, otherwise a nullptr.
1901-
static Decl *getPredefinedExprDecl(DeclContext *DC) {
1902-
while (DC && !isa<BlockDecl, CapturedDecl, FunctionDecl, ObjCMethodDecl>(DC))
1903-
DC = DC->getParent();
1904-
return cast_or_null<Decl>(DC);
1905-
}
1906-
19071897
static PredefinedIdentKind getPredefinedExprKind(tok::TokenKind Kind) {
19081898
switch (Kind) {
19091899
default:
@@ -1925,6 +1915,15 @@ static PredefinedIdentKind getPredefinedExprKind(tok::TokenKind Kind) {
19251915
}
19261916
}
19271917

1918+
/// getPredefinedExprDecl - Returns Decl of a given DeclContext that can be used
1919+
/// to determine the value of a PredefinedExpr. This can be either a
1920+
/// block, lambda, captured statement, function, otherwise a nullptr.
1921+
static Decl *getPredefinedExprDecl(DeclContext *DC) {
1922+
while (DC && !isa<BlockDecl, CapturedDecl, FunctionDecl, ObjCMethodDecl>(DC))
1923+
DC = DC->getParent();
1924+
return cast_or_null<Decl>(DC);
1925+
}
1926+
19281927
/// getUDSuffixLoc - Create a SourceLocation for a ud-suffix, given the
19291928
/// location of the token and the offset of the ud-suffix within it.
19301929
static SourceLocation getUDSuffixLoc(Sema &S, SourceLocation TokLoc,
@@ -2005,7 +2004,7 @@ Sema::ExpandFunctionLocalPredefinedMacros(ArrayRef<Token> Toks) {
20052004
// Note: Although function local macros are defined only inside functions,
20062005
// we ensure a valid `CurrentDecl` even outside of a function. This allows
20072006
// expansion of macros into empty string literals without additional checks.
2008-
Decl *CurrentDecl = getCurLocalScopeDecl();
2007+
Decl *CurrentDecl = getPredefinedExprDecl(CurContext);
20092008
if (!CurrentDecl)
20102009
CurrentDecl = Context.getTranslationUnitDecl();
20112010

@@ -2698,34 +2697,6 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
26982697
return ExprError();
26992698
}
27002699

2701-
// C++ [temp.dep.expr]p3:
2702-
// An id-expression is type-dependent if it contains:
2703-
// -- an identifier that was declared with a dependent type,
2704-
// (note: handled after lookup)
2705-
// -- a template-id that is dependent,
2706-
// (note: handled in BuildTemplateIdExpr)
2707-
// -- a conversion-function-id that specifies a dependent type,
2708-
// -- a nested-name-specifier that contains a class-name that
2709-
// names a dependent type.
2710-
// Determine whether this is a member of an unknown specialization;
2711-
// we need to handle these differently.
2712-
bool DependentID = false;
2713-
if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
2714-
Name.getCXXNameType()->isDependentType()) {
2715-
DependentID = true;
2716-
} else if (SS.isSet()) {
2717-
if (DeclContext *DC = computeDeclContext(SS, false)) {
2718-
if (RequireCompleteDeclContext(SS, DC))
2719-
return ExprError();
2720-
} else {
2721-
DependentID = true;
2722-
}
2723-
}
2724-
2725-
if (DependentID)
2726-
return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo,
2727-
IsAddressOfOperand, TemplateArgs);
2728-
27292700
// This specially handles arguments of attributes appertains to a type of C
27302701
// struct field such that the name lookup within a struct finds the member
27312702
// name, which is not the case for other contexts in C.

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -984,8 +984,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
984984
// arrow operator was used with a dependent non-pointer object expression,
985985
// build a CXXDependentScopeMemberExpr.
986986
if (R.wasNotFoundInCurrentInstantiation() ||
987-
(IsArrow && !BaseExprType->isPointerType() &&
988-
BaseExprType->isDependentType()))
987+
(R.getLookupName().getCXXOverloadedOperator() == OO_Equal &&
988+
(SS.isSet() ? SS.getScopeRep()->isDependent()
989+
: BaseExprType->isDependentType())))
989990
return ActOnDependentMemberExpr(BaseExpr, BaseExprType, IsArrow, OpLoc, SS,
990991
TemplateKWLoc, FirstQualifierInScope,
991992
R.getLookupNameInfo(), TemplateArgs);
@@ -1322,8 +1323,8 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
13221323
// was encountered while looking for the overloaded operator->.
13231324
if (!S.getLangOpts().CPlusPlus) {
13241325
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
1325-
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
1326-
<< FixItHint::CreateReplacement(OpLoc, ".");
1326+
<< BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
1327+
<< FixItHint::CreateReplacement(OpLoc, ".");
13271328
}
13281329
IsArrow = false;
13291330
} else {
@@ -1349,7 +1350,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
13491350
}
13501351

13511352
// Handle field access to simple records.
1352-
if (BaseType->getAsRecordDecl() || BaseType->isDependentType()) {
1353+
if (BaseType->getAsRecordDecl()) {
13531354
TypoExpr *TE = nullptr;
13541355
if (LookupMemberExprInRecord(S, R, BaseExpr.get(), BaseType, OpLoc, IsArrow,
13551356
SS, HasTemplateArgs, TemplateKWLoc, TE))

clang/lib/Sema/SemaLookup.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,31 +1286,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
12861286
if (DeclContext *DC = PreS->getEntity())
12871287
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
12881288
}
1289-
// C++23 [temp.dep.general]p2:
1290-
// The component name of an unqualified-id is dependent if
1291-
// - it is a conversion-function-id whose conversion-type-id
1292-
// is dependent, or
1293-
// - it is operator= and the current class is a templated entity, or
1294-
// - the unqualified-id is the postfix-expression in a dependent call.
1295-
if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName &&
1296-
Name.getCXXNameType()->isDependentType()) {
1297-
R.setNotFoundInCurrentInstantiation();
1298-
return false;
1299-
}
1300-
1301-
// If this is the name of an implicitly-declared special member function,
1302-
// go through the scope stack to implicitly declare
1303-
if (isImplicitlyDeclaredMemberFunctionName(Name)) {
1304-
for (Scope *PreS = S; PreS; PreS = PreS->getParent())
1305-
if (DeclContext *DC = PreS->getEntity()) {
1306-
if (DC->isDependentContext() && isa<CXXRecordDecl>(DC) &&
1307-
Name.getCXXOverloadedOperator() == OO_Equal) {
1308-
R.setNotFoundInCurrentInstantiation();
1309-
return false;
1310-
}
1311-
DeclareImplicitMemberFunctionsWithName(*this, Name, R.getNameLoc(), DC);
1312-
}
1313-
}
13141289

13151290
// C++23 [temp.dep.general]p2:
13161291
// The component name of an unqualified-id is dependent if

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,7 +4634,6 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
46344634
return ULE;
46354635
}
46364636

4637-
// We actually only call this from template instantiation.
46384637
ExprResult Sema::BuildQualifiedTemplateIdExpr(
46394638
CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
46404639
const DeclarationNameInfo &NameInfo,
@@ -9062,15 +9061,20 @@ bool Sema::CheckFunctionTemplateSpecialization(
90629061
Ovl->getDeclContext()->getRedeclContext()))
90639062
continue;
90649063

9064+
QualType FT = FD->getType();
9065+
// C++11 [dcl.constexpr]p8:
9066+
// A constexpr specifier for a non-static member function that is not
9067+
// a constructor declares that member function to be const.
9068+
//
90659069
// When matching a constexpr member function template specialization
90669070
// against the primary template, we don't yet know whether the
90679071
// specialization has an implicit 'const' (because we don't know whether
90689072
// it will be a static member function until we know which template it
9069-
// specializes), so adjust it now assuming it specializes this template.
9070-
QualType FT = FD->getType();
9071-
if (FD->isConstexpr()) {
9072-
CXXMethodDecl *OldMD =
9073-
dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
9073+
// specializes). This rule was removed in C++14.
9074+
if (auto *NewMD = dyn_cast<CXXMethodDecl>(FD);
9075+
!getLangOpts().CPlusPlus14 && NewMD && NewMD->isConstexpr() &&
9076+
!isa<CXXConstructorDecl, CXXDestructorDecl>(NewMD)) {
9077+
auto *OldMD = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
90749078
if (OldMD && OldMD->isConst()) {
90759079
const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
90769080
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();

clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -verify -std=c++17 %s
44
// RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only -verify -std=c++2a %s
55

6-
// XFAIL: *
7-
86
// MSVC always adopted the C++17 rule that implies that constexpr variables are
97
// implicitly inline, so do the test again.
108
// RUN: %clang_cc1 -triple x86_64-windows-msvc -DMS_ABI -fsyntax-only -verify -std=c++11 %s
@@ -91,6 +89,9 @@ struct S {
9189
template<typename T> constexpr T f(); // expected-warning 0-1{{C++14}} expected-note 0-1{{candidate}}
9290
template <typename T>
9391
T g() const; // expected-note-re {{candidate template ignored: could not match 'T (){{( __attribute__\(\(thiscall\)\))?}} const' against 'char (){{( __attribute__\(\(thiscall\)\))?}}'}}
92+
#if __cplusplus >= 201402L
93+
// expected-note@-2 {{candidate template ignored: could not match 'T () const' against 'int ()'}}
94+
#endif
9495
};
9596

9697
// explicit specialization can differ in constepxr
@@ -102,13 +103,17 @@ template <> notlit S::f() const { return notlit(); }
102103
#if __cplusplus >= 201402L
103104
// expected-error@-2 {{no function template matches}}
104105
#endif
105-
template <> constexpr int S::g() { return 0; } // expected-note {{previous}}
106+
template <> constexpr int S::g() { return 0; }
106107
#if __cplusplus < 201402L
107108
// expected-warning@-2 {{C++14}}
109+
// expected-note@-3 {{previous}}
108110
#else
109-
// expected-error@-4 {{does not match any declaration in 'S'}}
111+
// expected-error@-5 {{no function template matches function template specialization 'g'}}
112+
#endif
113+
template <> int S::g() const;
114+
#if __cplusplus < 201402L
115+
// expected-error@-2 {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
110116
#endif
111-
template <> int S::g() const; // expected-error {{non-constexpr declaration of 'g<int>' follows constexpr declaration}}
112117
// specializations can drop the 'constexpr' but not the implied 'const'.
113118
template <> char S::g() { return 0; } // expected-error {{no function template matches}}
114119
template <> double S::g() const { return 0; } // ok

clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// RUN:
2-
// DEACTIVATED: %clang_cc1 -Wno-unused-value -verify %s
1+
// RUN: %clang_cc1 -Wno-unused-value -verify %s
32

43
namespace N0 {
54
struct A {

clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify=expected,cxx11 %s
22
// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify=expected,since-cxx14 %s
33

4-
// XFAIL:*
5-
4+
// XFAIL: *
65
struct A {
76
template<typename T>
87
void f0();
@@ -33,7 +32,7 @@ constexpr void A::f1<long>(); // since-cxx14-error {{no function template matche
3332
// members of a class template explicitly specialized for an implicitly
3433
// instantiated specialization of that template.
3534
template<typename T>
36-
struct B { // #defined-here
35+
struct B {
3736
void g0(); // since-cxx14-note {{previous declaration is here}}
3837
// cxx11-note@-1 {{member declaration does not match because it is not const qualified}}
3938

@@ -51,13 +50,11 @@ template<>
5150
constexpr void B<short>::g0(); // since-cxx14-error {{constexpr declaration of 'g0' follows non-constexpr declaration}}
5251
// cxx11-error@-1 {{out-of-line declaration of 'g0' does not match any declaration in 'B<short>'}}
5352
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
54-
// expected-note@#defined-here {{defined here}}
5553

5654
template<>
5755
constexpr void B<short>::g1(); // since-cxx14-error {{out-of-line declaration of 'g1' does not match any declaration in 'B<short>'}}
5856
// cxx11-error@-1 {{constexpr declaration of 'g1' follows non-constexpr declaration}}
5957
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
60-
// expected-note@#defined-here {{defined here}}
6158

6259
template<>
6360
template<typename U>
@@ -70,3 +67,5 @@ template<typename U>
7067
constexpr void B<long>::h1(); // since-cxx14-error {{out-of-line declaration of 'h1' does not match any declaration in 'B<long>'}}
7168
// cxx11-error@-1 {{constexpr declaration of 'h1' follows non-constexpr declaration}}
7269
// cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
70+
71+

clang/test/Sema/ms_predefined_expr.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,40 @@ void test_static_assert() {
169169
void test_char_injection(decltype(sizeof('"')), decltype(sizeof("()"))) {
170170
unused("" __FUNCSIG__); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}}
171171
}
172+
173+
void test_in_struct_init() {
174+
struct {
175+
char F[sizeof(__FUNCTION__)];
176+
} s1 = { __FUNCTION__ }; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}}
177+
178+
struct {
179+
char F[sizeof("F:" __FUNCTION__)]; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
180+
} s2 = { "F:" __FUNCTION__ }; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
181+
182+
class C {
183+
public:
184+
struct {
185+
char F[sizeof(__FUNCTION__)];
186+
} s;
187+
} c1 = { { __FUNCTION__ } }; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}}
188+
}
189+
190+
void test_in_constexpr_struct_init() {
191+
struct {
192+
char F[sizeof(__FUNCTION__)];
193+
} constexpr s1 = { __FUNCTION__ }; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}}
194+
ASSERT_EQ(__FUNCTION__, s1.F);
195+
196+
struct {
197+
char F[sizeof("F:" __FUNCTION__)]; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
198+
} constexpr s2 = { "F:" __FUNCTION__ }; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
199+
ASSERT_EQ("F:" __FUNCTION__, s2.F); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
200+
201+
class C {
202+
public:
203+
struct {
204+
char F[sizeof("F:" __FUNCTION__)]; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
205+
} s;
206+
} constexpr c1 = { { "F:" __FUNCTION__ } }; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
207+
ASSERT_EQ("F:" __FUNCTION__, c1.s.F); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}}
208+
}

0 commit comments

Comments
 (0)