diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3614,9 +3614,10 @@ /// in a 'block', this returns the containing context. NamedDecl *getCurFunctionOrMethodDecl() const; - /// getCurLocalScopeDecl - Return the Decl for either of: - /// block, lambda, captured statement, function, or nullptr. - Decl *getCurLocalScopeDecl(); + /// Returns the current DeclContext that can be used to determine the value + /// for PredefinedExpr. This can be either a block, lambda, captured + /// statement, function, otherwise a nullptr. + DeclContext *getPredefinedExprDeclContext(); /// Add this decl to the scope shadowed decl chains. void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7524,6 +7524,9 @@ return Error(E); } + bool VisitPredefinedExpr(const PredefinedExpr *E) { + return StmtVisitorTy::Visit(E->getFunctionName()); + } bool VisitConstantExpr(const ConstantExpr *E) { if (E->hasAPValueResult()) return DerivedSuccess(E->getAPValueResult(), E); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1491,16 +1491,11 @@ return nullptr; } -Decl *Sema::getCurLocalScopeDecl() { - if (const BlockScopeInfo *BSI = getCurBlock()) - return BSI->TheDecl; - if (const LambdaScopeInfo *LSI = getCurLambda()) - return LSI->CallOperator; - if (const CapturedRegionScopeInfo *CSI = getCurCapturedRegion()) - return CSI->TheCapturedDecl; - if (NamedDecl *ND = getCurFunctionOrMethodDecl()) - return ND; - return nullptr; +DeclContext *Sema::getPredefinedExprDeclContext() { + DeclContext *DC = CurContext; + while (DC && !isa(DC)) + DC = DC->getParent(); + return DC; } LangAS Sema::getDefaultCXXMethodAddrSpace() const { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1984,7 +1984,7 @@ // Note: Although function local macros are defined only inside functions, // we ensure a valid `CurrentDecl` even outside of a function. This allows // expansion of macros into empty string literals without additional checks. - Decl *CurrentDecl = getCurLocalScopeDecl(); + Decl *CurrentDecl = cast_or_null(getPredefinedExprDeclContext()); if (!CurrentDecl) CurrentDecl = Context.getTranslationUnitDecl(); @@ -3705,7 +3705,7 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentKind IK) { - Decl *currentDecl = getCurLocalScopeDecl(); + Decl *currentDecl = cast_or_null(getPredefinedExprDeclContext()); if (!currentDecl) { Diag(Loc, diag::ext_predef_outside_function); currentDecl = Context.getTranslationUnitDecl(); diff --git a/clang/test/Sema/ms_predefined_expr.cpp b/clang/test/Sema/ms_predefined_expr.cpp --- a/clang/test/Sema/ms_predefined_expr.cpp +++ b/clang/test/Sema/ms_predefined_expr.cpp @@ -168,3 +168,40 @@ void test_char_injection(decltype(sizeof('"')), decltype(sizeof("()"))) { unused("" __FUNCSIG__); // expected-warning{{expansion of predefined identifier '__FUNCSIG__' to a string literal is a Microsoft extension}} } + +void test_in_struct_init() { + struct { + char F[sizeof(__FUNCTION__)]; + } s1 = { __FUNCTION__ }; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}} + + struct { + char F[sizeof("F:" __FUNCTION__)]; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + } s2 = { "F:" __FUNCTION__ }; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + + class C { + public: + struct { + char F[sizeof(__FUNCTION__)]; + } s; + } c1 = { { __FUNCTION__ } }; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}} +} + +void test_in_constexpr_struct_init() { + struct { + char F[sizeof(__FUNCTION__)]; + } constexpr s1 = { __FUNCTION__ }; // expected-warning{{initializing an array from a '__FUNCTION__' predefined identifier is a Microsoft extension}} + ASSERT_EQ(__FUNCTION__, s1.F); + + struct { + char F[sizeof("F:" __FUNCTION__)]; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + } constexpr s2 = { "F:" __FUNCTION__ }; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ("F:" __FUNCTION__, s2.F); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + + class C { + public: + struct { + char F[sizeof("F:" __FUNCTION__)]; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + } s; + } constexpr c1 = { { "F:" __FUNCTION__ } }; // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} + ASSERT_EQ("F:" __FUNCTION__, c1.s.F); // expected-warning{{expansion of predefined identifier '__FUNCTION__' to a string literal is a Microsoft extension}} +}