diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 734cffd01c223..0bbd1f6be4e2e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8845,6 +8845,9 @@ def warn_redefine_extname_not_applied : Warning< // inline asm. let CategoryName = "Inline Assembly Issue" in { + def err_asm_pmf_through_constraint_not_permitted + : Error<"cannot pass a pointer-to-member through register-constrained " + "inline assembly parameter">; def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; def err_asm_invalid_output_constraint : Error< "invalid output constraint '%0' in asm">; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index d19f4d6c78356..06fc0ec798660 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -377,6 +377,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, Expr *InputExpr = Exprs[i]; + if (InputExpr->getType()->isMemberPointerType()) + return StmtError(Diag(InputExpr->getBeginLoc(), + diag::err_asm_pmf_through_constraint_not_permitted) + << InputExpr->getSourceRange()); + // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(InputExpr, *this)) return StmtError(); diff --git a/clang/test/Sema/gnu-asm-pmf.cpp b/clang/test/Sema/gnu-asm-pmf.cpp new file mode 100644 index 0000000000000..30677c85696df --- /dev/null +++ b/clang/test/Sema/gnu-asm-pmf.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -std=c++2b -fsyntax-only %s -verify +// RUN: %clang_cc1 -triple x86_64-unknown-windows-itanium -std=c++2b -fsyntax-only %s -verify + +struct S { + void operator()(); +}; + +struct T { + virtual void operator()(); +}; + +struct U { + static void operator()(); +}; + +struct V: virtual T { + virtual void f(); +}; + +struct W : virtual V { + int i; +}; + +struct X { + __UINTPTR_TYPE__ ptr; + __UINTPTR_TYPE__ adj; +}; + +auto L = [](){}; + +void f() { + auto pmf = &S::operator(); + + __asm__ __volatile__ ("" : : "r"(&decltype(L)::operator())); + // expected-error@-1{{cannot pass a pointer-to-member through register-constrained inline assembly parameter}} + __asm__ __volatile__ ("" : : "r"(&S::operator())); + // expected-error@-1{{cannot pass a pointer-to-member through register-constrained inline assembly parameter}} + __asm__ __volatile__ ("" : : "r"(&T::operator())); + // expected-error@-1{{cannot pass a pointer-to-member through register-constrained inline assembly parameter}} + __asm__ __volatile__ ("" : : "r"(pmf)); + // expected-error@-1{{cannot pass a pointer-to-member through register-constrained inline assembly parameter}} + __asm__ __volatile__ ("" : : "r"(&W::f)); + // expected-error@-1{{cannot pass a pointer-to-member through register-constrained inline assembly parameter}} + __asm__ __volatile__ ("" : : "r"(&W::i)); + // expected-error@-1{{cannot pass a pointer-to-member through register-constrained inline assembly parameter}} + + __asm__ __volatile__ ("" : : "r"(X{0,0})); + __asm__ __volatile__ ("" : : "r"(&U::operator())); +}