Fix IR generation for member access with a prvalue on the RHS

For historical reasons, the extractor marks the temporary object expression used as the qualifier of a member access as a prvalue(load), even though the current C++ standard says that the temporary object materialization results in a glvalue. Added some special handling to ignore the load for both field accesses and member function calls.

This fixes all of the consistency failures in our regular tests, and all of the related failures in `syntax-zoo` other than the ones that deal with pointers-to-member, which aren't really supported yet anyway.
This commit is contained in:
Dave Bartolomeo
2020-10-20 12:53:47 -04:00
parent 735c657326
commit 4ba281731c
9 changed files with 76 additions and 82 deletions

View File

@@ -22,14 +22,7 @@ wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
| ir.cpp:1401:45:1401:45 | FieldAddress: y | FieldAddress instruction 'FieldAddress: y' has an object address operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
thisArgumentIsNonPointer
| ir.cpp:1373:14:1373:18 | Call: call to c_str | Call instruction 'Call: call to c_str' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1365:6:1365:21 | void temporary_string() | void temporary_string() |
| ir.cpp:1374:27:1374:31 | Call: call to c_str | Call instruction 'Call: call to c_str' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1365:6:1365:21 | void temporary_string() | void temporary_string() |
| ir.cpp:1385:23:1385:28 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1379:6:1379:30 | void temporary_destructor_only() | void temporary_destructor_only() |
| ir.cpp:1386:36:1386:41 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1379:6:1379:30 | void temporary_destructor_only() | void temporary_destructor_only() |
| ir.cpp:1397:24:1397:29 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
| ir.cpp:1398:37:1398:42 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -7564,25 +7564,23 @@ ir.cpp:
# 1373| v1373_4(void) = Call[String] : func:r1373_3, this:r1373_1
# 1373| mu1373_5(unknown) = ^CallSideEffect : ~m?
# 1373| mu1373_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r1373_1
# 1373| r1373_7(String) = Load[#temp1373:5] : &:r1373_1, ~m?
# 1373| r1373_8(String) = Convert : r1373_7
# 1373| r1373_9(glval<unknown>) = FunctionAddress[c_str] :
# 1373| r1373_10(char *) = Call[c_str] : func:r1373_9, this:r1373_8
# 1373| mu1373_11(unknown) = ^CallSideEffect : ~m?
# 1373| v1373_12(void) = ^BufferReadSideEffect[-1] : &:r1373_8, ~m?
# 1373| mu1373_13(String) = ^IndirectMayWriteSideEffect[-1] : &:r1373_8
# 1373| r1373_7(glval<String>) = Convert : r1373_1
# 1373| r1373_8(glval<unknown>) = FunctionAddress[c_str] :
# 1373| r1373_9(char *) = Call[c_str] : func:r1373_8, this:r1373_7
# 1373| mu1373_10(unknown) = ^CallSideEffect : ~m?
# 1373| v1373_11(void) = ^BufferReadSideEffect[-1] : &:r1373_7, ~m?
# 1373| mu1373_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r1373_7
# 1374| r1374_1(glval<String>) = VariableAddress[#temp1374:5] :
# 1374| r1374_2(glval<unknown>) = FunctionAddress[returnValue] :
# 1374| r1374_3(String) = Call[returnValue] : func:r1374_2
# 1374| mu1374_4(unknown) = ^CallSideEffect : ~m?
# 1374| mu1374_5(String) = Store[#temp1374:5] : &:r1374_1, r1374_3
# 1374| r1374_6(String) = Load[#temp1374:5] : &:r1374_1, ~m?
# 1374| r1374_7(String) = Convert : r1374_6
# 1374| r1374_8(glval<unknown>) = FunctionAddress[c_str] :
# 1374| r1374_9(char *) = Call[c_str] : func:r1374_8, this:r1374_7
# 1374| mu1374_10(unknown) = ^CallSideEffect : ~m?
# 1374| v1374_11(void) = ^BufferReadSideEffect[-1] : &:r1374_7, ~m?
# 1374| mu1374_12(String) = ^IndirectMayWriteSideEffect[-1] : &:r1374_7
# 1374| r1374_6(glval<String>) = Convert : r1374_1
# 1374| r1374_7(glval<unknown>) = FunctionAddress[c_str] :
# 1374| r1374_8(char *) = Call[c_str] : func:r1374_7, this:r1374_6
# 1374| mu1374_9(unknown) = ^CallSideEffect : ~m?
# 1374| v1374_10(void) = ^BufferReadSideEffect[-1] : &:r1374_6, ~m?
# 1374| mu1374_11(String) = ^IndirectMayWriteSideEffect[-1] : &:r1374_6
# 1376| r1376_1(glval<String>) = VariableAddress[#temp1376:5] :
# 1376| r1376_2(glval<unknown>) = FunctionAddress[defaultConstruct] :
# 1376| r1376_3(String) = Call[defaultConstruct] : func:r1376_2
@@ -7634,23 +7632,21 @@ ir.cpp:
# 1385| r1385_1(glval<destructor_only>) = VariableAddress[#temp1385:5] :
# 1385| r1385_2(destructor_only) = Constant[0] :
# 1385| mu1385_3(destructor_only) = Store[#temp1385:5] : &:r1385_1, r1385_2
# 1385| r1385_4(destructor_only) = Load[#temp1385:5] : &:r1385_1, ~m?
# 1385| r1385_5(glval<unknown>) = FunctionAddress[method] :
# 1385| v1385_6(void) = Call[method] : func:r1385_5, this:r1385_4
# 1385| mu1385_7(unknown) = ^CallSideEffect : ~m?
# 1385| v1385_8(void) = ^BufferReadSideEffect[-1] : &:r1385_4, ~m?
# 1385| mu1385_9(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1385_4
# 1385| r1385_4(glval<unknown>) = FunctionAddress[method] :
# 1385| v1385_5(void) = Call[method] : func:r1385_4, this:r1385_1
# 1385| mu1385_6(unknown) = ^CallSideEffect : ~m?
# 1385| v1385_7(void) = ^BufferReadSideEffect[-1] : &:r1385_1, ~m?
# 1385| mu1385_8(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1385_1
# 1386| r1386_1(glval<destructor_only>) = VariableAddress[#temp1386:5] :
# 1386| r1386_2(glval<unknown>) = FunctionAddress[returnValue] :
# 1386| r1386_3(destructor_only) = Call[returnValue] : func:r1386_2
# 1386| mu1386_4(unknown) = ^CallSideEffect : ~m?
# 1386| mu1386_5(destructor_only) = Store[#temp1386:5] : &:r1386_1, r1386_3
# 1386| r1386_6(destructor_only) = Load[#temp1386:5] : &:r1386_1, ~m?
# 1386| r1386_7(glval<unknown>) = FunctionAddress[method] :
# 1386| v1386_8(void) = Call[method] : func:r1386_7, this:r1386_6
# 1386| mu1386_9(unknown) = ^CallSideEffect : ~m?
# 1386| v1386_10(void) = ^BufferReadSideEffect[-1] : &:r1386_6, ~m?
# 1386| mu1386_11(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1386_6
# 1386| r1386_6(glval<unknown>) = FunctionAddress[method] :
# 1386| v1386_7(void) = Call[method] : func:r1386_6, this:r1386_1
# 1386| mu1386_8(unknown) = ^CallSideEffect : ~m?
# 1386| v1386_9(void) = ^BufferReadSideEffect[-1] : &:r1386_1, ~m?
# 1386| mu1386_10(destructor_only) = ^IndirectMayWriteSideEffect[-1] : &:r1386_1
# 1388| r1388_1(glval<destructor_only>) = VariableAddress[#temp1388:5] :
# 1388| r1388_2(glval<unknown>) = FunctionAddress[defaultConstruct] :
# 1388| r1388_3(destructor_only) = Call[defaultConstruct] : func:r1388_2
@@ -7716,23 +7712,21 @@ ir.cpp:
# 1397| v1397_4(void) = Call[copy_constructor] : func:r1397_3, this:r1397_1
# 1397| mu1397_5(unknown) = ^CallSideEffect : ~m?
# 1397| mu1397_6(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1397_1
# 1397| r1397_7(copy_constructor) = Load[#temp1397:5] : &:r1397_1, ~m?
# 1397| r1397_8(glval<unknown>) = FunctionAddress[method] :
# 1397| v1397_9(void) = Call[method] : func:r1397_8, this:r1397_7
# 1397| mu1397_10(unknown) = ^CallSideEffect : ~m?
# 1397| v1397_11(void) = ^BufferReadSideEffect[-1] : &:r1397_7, ~m?
# 1397| mu1397_12(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1397_7
# 1397| r1397_7(glval<unknown>) = FunctionAddress[method] :
# 1397| v1397_8(void) = Call[method] : func:r1397_7, this:r1397_1
# 1397| mu1397_9(unknown) = ^CallSideEffect : ~m?
# 1397| v1397_10(void) = ^BufferReadSideEffect[-1] : &:r1397_1, ~m?
# 1397| mu1397_11(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1397_1
# 1398| r1398_1(glval<copy_constructor>) = VariableAddress[#temp1398:5] :
# 1398| r1398_2(glval<unknown>) = FunctionAddress[returnValue] :
# 1398| r1398_3(copy_constructor) = Call[returnValue] : func:r1398_2
# 1398| mu1398_4(unknown) = ^CallSideEffect : ~m?
# 1398| mu1398_5(copy_constructor) = Store[#temp1398:5] : &:r1398_1, r1398_3
# 1398| r1398_6(copy_constructor) = Load[#temp1398:5] : &:r1398_1, ~m?
# 1398| r1398_7(glval<unknown>) = FunctionAddress[method] :
# 1398| v1398_8(void) = Call[method] : func:r1398_7, this:r1398_6
# 1398| mu1398_9(unknown) = ^CallSideEffect : ~m?
# 1398| v1398_10(void) = ^BufferReadSideEffect[-1] : &:r1398_6, ~m?
# 1398| mu1398_11(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1398_6
# 1398| r1398_6(glval<unknown>) = FunctionAddress[method] :
# 1398| v1398_7(void) = Call[method] : func:r1398_6, this:r1398_1
# 1398| mu1398_8(unknown) = ^CallSideEffect : ~m?
# 1398| v1398_9(void) = ^BufferReadSideEffect[-1] : &:r1398_1, ~m?
# 1398| mu1398_10(copy_constructor) = ^IndirectMayWriteSideEffect[-1] : &:r1398_1
# 1399| r1399_1(glval<copy_constructor>) = VariableAddress[#temp1399:5] :
# 1399| r1399_2(glval<unknown>) = FunctionAddress[defaultConstruct] :
# 1399| r1399_3(copy_constructor) = Call[defaultConstruct] : func:r1399_2
@@ -7745,9 +7739,8 @@ ir.cpp:
# 1401| r1401_4(copy_constructor) = Call[returnValue] : func:r1401_3
# 1401| mu1401_5(unknown) = ^CallSideEffect : ~m?
# 1401| mu1401_6(copy_constructor) = Store[#temp1401:13] : &:r1401_2, r1401_4
# 1401| r1401_7(copy_constructor) = Load[#temp1401:13] : &:r1401_2, ~m?
# 1401| r1401_8(glval<int>) = FieldAddress[y] : r1401_7
# 1401| mu1401_9(int) = Store[y] : &:r1401_1, r1401_8
# 1401| r1401_7(glval<int>) = FieldAddress[y] : r1401_2
# 1401| mu1401_8(int) = Store[y] : &:r1401_1, r1401_7
# 1402| v1402_1(void) = NoOp :
# 1391| v1391_4(void) = ReturnVoid :
# 1391| v1391_5(void) = AliasedUse : ~m?

View File

@@ -22,14 +22,7 @@ wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
| ir.cpp:1401:45:1401:45 | FieldAddress: y | FieldAddress instruction 'FieldAddress: y' has an object address operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
thisArgumentIsNonPointer
| ir.cpp:1373:14:1373:18 | Call: call to c_str | Call instruction 'Call: call to c_str' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1365:6:1365:21 | void temporary_string() | void temporary_string() |
| ir.cpp:1374:27:1374:31 | Call: call to c_str | Call instruction 'Call: call to c_str' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1365:6:1365:21 | void temporary_string() | void temporary_string() |
| ir.cpp:1385:23:1385:28 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1379:6:1379:30 | void temporary_destructor_only() | void temporary_destructor_only() |
| ir.cpp:1386:36:1386:41 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1379:6:1379:30 | void temporary_destructor_only() | void temporary_destructor_only() |
| ir.cpp:1397:24:1397:29 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
| ir.cpp:1398:37:1398:42 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -22,14 +22,7 @@ wronglyMarkedAsConflated
invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
| ir.cpp:1401:45:1401:45 | FieldAddress: y | FieldAddress instruction 'FieldAddress: y' has an object address operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
thisArgumentIsNonPointer
| ir.cpp:1373:14:1373:18 | Call: call to c_str | Call instruction 'Call: call to c_str' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1365:6:1365:21 | void temporary_string() | void temporary_string() |
| ir.cpp:1374:27:1374:31 | Call: call to c_str | Call instruction 'Call: call to c_str' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1365:6:1365:21 | void temporary_string() | void temporary_string() |
| ir.cpp:1385:23:1385:28 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1379:6:1379:30 | void temporary_destructor_only() | void temporary_destructor_only() |
| ir.cpp:1386:36:1386:41 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1379:6:1379:30 | void temporary_destructor_only() | void temporary_destructor_only() |
| ir.cpp:1397:24:1397:29 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
| ir.cpp:1398:37:1398:42 | Call: call to method | Call instruction 'Call: call to method' has a `this` argument operand that is not an address, in function '$@'. | ir.cpp:1391:6:1391:31 | void temporary_copy_constructor() | void temporary_copy_constructor() |
missingCanonicalLanguageType
multipleCanonicalLanguageTypes
missingIRType

View File

@@ -96,10 +96,6 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
| conditional_destructors.cpp:30:15:30:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() |
| conditional_destructors.cpp:33:15:33:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() |
| conditional_destructors.cpp:39:15:39:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() |
| conditional_destructors.cpp:42:15:42:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() |
| pmcallexpr.cpp:8:2:8:15 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() |
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |

View File

@@ -153,14 +153,6 @@ fieldAddressOnNonPointer
| misc.c:220:9:223:3 | FieldAddress: {...} | FieldAddress instruction 'FieldAddress: {...}' has an object address operand that is not an address, in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) |
| misc.c:220:9:223:3 | FieldAddress: {...} | FieldAddress instruction 'FieldAddress: {...}' has an object address operand that is not an address, in function '$@'. | misc.c:219:5:219:26 | int assign_designated_init(someStruct*) | int assign_designated_init(someStruct*) |
thisArgumentIsNonPointer
| condition_decls.cpp:16:15:16:15 | Call: call to operator int | Call instruction 'Call: call to operator int' has a `this` argument operand that is not an address, in function '$@'. | condition_decls.cpp:15:6:15:17 | void if_decl_bind(int) | void if_decl_bind(int) |
| condition_decls.cpp:26:19:26:19 | Call: call to operator int | Call instruction 'Call: call to operator int' has a `this` argument operand that is not an address, in function '$@'. | condition_decls.cpp:25:6:25:21 | void switch_decl_bind(int) | void switch_decl_bind(int) |
| condition_decls.cpp:41:18:41:18 | Call: call to operator int | Call instruction 'Call: call to operator int' has a `this` argument operand that is not an address, in function '$@'. | condition_decls.cpp:40:6:40:20 | void while_decl_bind(int) | void while_decl_bind(int) |
| condition_decls.cpp:48:48:48:48 | Call: call to operator int | Call instruction 'Call: call to operator int' has a `this` argument operand that is not an address, in function '$@'. | condition_decls.cpp:47:6:47:18 | void for_decl_bind(int) | void for_decl_bind(int) |
| conditional_destructors.cpp:30:15:30:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() |
| conditional_destructors.cpp:33:15:33:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() |
| conditional_destructors.cpp:39:15:39:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() |
| conditional_destructors.cpp:42:15:42:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() |
| pmcallexpr.cpp:8:2:8:15 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() |
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |

View File

@@ -96,10 +96,6 @@ invalidOverlap
nonUniqueEnclosingIRFunction
fieldAddressOnNonPointer
thisArgumentIsNonPointer
| conditional_destructors.cpp:30:15:30:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() |
| conditional_destructors.cpp:33:15:33:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:29:6:29:7 | void f1() | void f1() |
| conditional_destructors.cpp:39:15:39:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() |
| conditional_destructors.cpp:42:15:42:15 | Call: call to operator== | Call instruction 'Call: call to operator==' has a `this` argument operand that is not an address, in function '$@'. | conditional_destructors.cpp:38:6:38:7 | void f2() | void f2() |
| pmcallexpr.cpp:8:2:8:15 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | array_delete.cpp:5:6:5:6 | void f() | void f() |
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |