ismailp added you to the CC list for the revision "C++11: if decl-specifier has 'friend' or 'static', do not allow access to 'this' pointer when parsing function declarator.".
Hi rsmith, rjmccall, Hi, the problem was discovered after bug #15290. My initial patch was merely masking the issue, and offered no real fix. Richard Smith suggested parser doesn't take 'friend' specifier into account when checking whether a method can access 'this' pointer to form a class member access expression. Operands of decltype and noexcept are unevaluated operands. Unevaluated operands cannot explicitly contain 'this' pointer, but non-static class member may be named ([expr]/p7). This expression should not be transform into a class member access expression, which is the purpose of this patch. After Richard has shown the problem, I have also added a check for static methods. http://llvm-reviews.chandlerc.com/D468 Files: lib/Parse/ParseDecl.cpp test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -4807,12 +4807,16 @@ // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq // and the end of the function-definition, member-declarator, or // declarator. + bool IsMemberContext = D.getContext() == Declarator::MemberContext; bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && - (D.getContext() == Declarator::MemberContext || + (IsMemberContext || (D.getContext() == Declarator::FileContext && D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord())); + Actions.CurContext->isRecord())) && + !(IsMemberContext && + (D.getDeclSpec().isFriendSpecified() || + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)); Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), DS.getTypeQualifiers() | Index: test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp =================================================================== --- test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp +++ test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp @@ -64,12 +64,12 @@ namespace Static { struct X1 { int m; - static auto f() -> decltype(m); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} - static auto g() -> decltype(this->m); // expected-error{{'this' cannot be used in a static member function declaration}} + static auto f() -> decltype(m); + static auto g() -> decltype(this->m); // expected-error{{invalid use of 'this' outside of a non-static member function}} static int h(); - static int i() noexcept(noexcept(m + 2)); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} + static int i() noexcept(noexcept(m + 2)); }; auto X1::h() -> decltype(m) { return 0; } // expected-error{{'this' cannot be implicitly used in a static member function declaration}} @@ -99,3 +99,34 @@ void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // expected-error {{cannot bind to a value of unrelated type}} }; } + +namespace unevaluated_operands { + template<typename T> + class noexcept_operand_template { + T v_; + friend int add_to_v(noexcept_operand_template &t) noexcept(noexcept(v_ + 42)) + { + return t.v_ + 42; + } + public: + static int sub_from_v(noexcept_operand_template &t) noexcept(noexcept(v_ - 42)) + { + return t.v_ - 42; + } + }; + + void dont_transform_cxx_member_expr() + { + noexcept_operand_template<int> t; + add_to_v(t); + noexcept_operand_template<int>::sub_from_v(t); + } + + struct decltype_operand { + int v_; + friend auto i() -> decltype(v_); + static auto j() -> decltype(v_); + friend auto f() -> decltype(this); // expected-error{{invalid use of 'this' outside of a non-static member function}} + static auto k() -> decltype(this->v_); // expected-error{{invalid use of 'this' outside of a non-static member function}} + }; +}
Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -4807,12 +4807,16 @@ // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq // and the end of the function-definition, member-declarator, or // declarator. + bool IsMemberContext = D.getContext() == Declarator::MemberContext; bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && - (D.getContext() == Declarator::MemberContext || + (IsMemberContext || (D.getContext() == Declarator::FileContext && D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord())); + Actions.CurContext->isRecord())) && + !(IsMemberContext && + (D.getDeclSpec().isFriendSpecified() || + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)); Sema::CXXThisScopeRAII ThisScope(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), DS.getTypeQualifiers() | Index: test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp =================================================================== --- test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp +++ test/CXX/expr/expr.prim/expr.prim.general/p3-0x.cpp @@ -64,12 +64,12 @@ namespace Static { struct X1 { int m; - static auto f() -> decltype(m); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} - static auto g() -> decltype(this->m); // expected-error{{'this' cannot be used in a static member function declaration}} + static auto f() -> decltype(m); + static auto g() -> decltype(this->m); // expected-error{{invalid use of 'this' outside of a non-static member function}} static int h(); - static int i() noexcept(noexcept(m + 2)); // expected-error{{'this' cannot be implicitly used in a static member function declaration}} + static int i() noexcept(noexcept(m + 2)); }; auto X1::h() -> decltype(m) { return 0; } // expected-error{{'this' cannot be implicitly used in a static member function declaration}} @@ -99,3 +99,34 @@ void foo(Derived& d) noexcept(noexcept(d.bar(d))) {} // expected-error {{cannot bind to a value of unrelated type}} }; } + +namespace unevaluated_operands { + template<typename T> + class noexcept_operand_template { + T v_; + friend int add_to_v(noexcept_operand_template &t) noexcept(noexcept(v_ + 42)) + { + return t.v_ + 42; + } + public: + static int sub_from_v(noexcept_operand_template &t) noexcept(noexcept(v_ - 42)) + { + return t.v_ - 42; + } + }; + + void dont_transform_cxx_member_expr() + { + noexcept_operand_template<int> t; + add_to_v(t); + noexcept_operand_template<int>::sub_from_v(t); + } + + struct decltype_operand { + int v_; + friend auto i() -> decltype(v_); + static auto j() -> decltype(v_); + friend auto f() -> decltype(this); // expected-error{{invalid use of 'this' outside of a non-static member function}} + static auto k() -> decltype(this->v_); // expected-error{{invalid use of 'this' outside of a non-static member function}} + }; +}
_______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits