Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6350,6 +6350,8 @@ def err_bad_memptr_lhs : Error< "left hand operand to %0 must be a %select{|pointer to }1class " "compatible with the right hand operand, but is %2">; +def err_memptr_incomplete : Error< + "member pointer has incomplete base type %0">; def warn_exception_caught_by_earlier_handler : Warning< "exception of type %0 will be caught by earlier handler">, InGroup; Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -247,6 +247,10 @@ LANGOPT(IncludeDefaultHeader, 1, 0, "Include default header file for OpenCL") BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing") LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime") +LANGOPT( + CompleteMemberPointers, 1, 0, + "Require member pointer base types to be complete at the point where the " + "type's inheritance model would be determined under the Microsoft ABI") ENUM_LANGOPT(GC, GCMode, 2, NonGC, "Objective-C Garbage Collection mode") ENUM_LANGOPT(ValueVisibilityMode, Visibility, 3, DefaultVisibility, Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -782,6 +782,12 @@ def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group, Flags<[CC1Option]>; def fcommon : Flag<["-"], "fcommon">, Group; def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group; +def fcomplete_member_pointers : Flag<["-"], "fcomplete-member-pointers">, Group, + Flags<[CoreOption, CC1Option]>, + HelpText<"Require member pointer base types to be complete if they would be significant under the Microsoft ABI">; +def fno_complete_member_pointers : Flag<["-"], "fno-complete-member-pointers">, Group, + Flags<[CoreOption]>, + HelpText<"Do not require member pointer base types to be complete if they would be significant under the Microsoft ABI">; def fconstant_cfstrings : Flag<["-"], "fconstant-cfstrings">, Group; def fconstant_string_class_EQ : Joined<["-"], "fconstant-string-class=">, Group; def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group; Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4784,6 +4784,10 @@ CmdArgs.push_back("-fforce-enable-int128"); } + if (Args.hasFlag(options::OPT_fcomplete_member_pointers, + options::OPT_fno_complete_member_pointers, false)) + CmdArgs.push_back("-fcomplete-member-pointers"); + // Finally add the compile command to the compilation. if (Args.hasArg(options::OPT__SLASH_fallback) && Output.getType() == types::TY_Object && Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -2754,6 +2754,8 @@ << A->getAsString(Args) << A->getValue(); } } + + Opts.CompleteMemberPointers = Args.hasArg(OPT_fcomplete_member_pointers); } static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -7585,11 +7585,17 @@ // assert(!T->isDependentType() && // "Can't ask whether a dependent type is complete"); - // We lock in the inheritance model once somebody has asked us to ensure - // that a pointer-to-member type is complete. - if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { - if (const MemberPointerType *MPTy = T->getAs()) { - if (!MPTy->getClass()->isDependentType()) { + if (const MemberPointerType *MPTy = T->getAs()) { + if (!MPTy->getClass()->isDependentType()) { + if (getLangOpts().CompleteMemberPointers && + !MPTy->getClass()->getAsCXXRecordDecl()->isBeingDefined() && + RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), + diag::err_memptr_incomplete)) + return true; + + // We lock in the inheritance model once somebody has asked us to ensure + // that a pointer-to-member type is complete. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { (void)isCompleteType(Loc, QualType(MPTy->getClass(), 0)); assignInheritanceModel(*this, MPTy->getMostRecentCXXRecordDecl()); } Index: test/Driver/complete-member-pointers.cpp =================================================================== --- test/Driver/complete-member-pointers.cpp +++ test/Driver/complete-member-pointers.cpp @@ -0,0 +1,7 @@ +// RUN: %clangxx -### -c %s -o %t.o -target x86_64-unknown-linux 2>&1 | FileCheck --check-prefix=NOFLAG %s +// RUN: %clangxx -### -c %s -o %t.o -target x86_64-unknown-linux -fcomplete-member-pointers 2>&1 | FileCheck %s +// RUN: %clangxx -### -c %s -o %t.o -target x86_64-unknown-linux -fcomplete-member-pointers -fno-complete-member-pointers 2>&1 | FileCheck --check-prefix=NOFLAG %s +// RUN: %clang_cl -### /c %s /Fo%t.o -target x86_64-pc-win32 -fcomplete-member-pointers 2>&1 | FileCheck %s + +// CHECK: "-fcomplete-member-pointers" +// NOFLAG-NOT: "-fcomplete-member-pointers" Index: test/SemaCXX/complete-member-pointers.cpp =================================================================== --- test/SemaCXX/complete-member-pointers.cpp +++ test/SemaCXX/complete-member-pointers.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify -fsyntax-only -fcomplete-member-pointers %s + +struct S; // expected-note {{forward declaration of 'S'}} +typedef int S::*t; +t foo; // expected-error {{member pointer has incomplete base type 'S'}} + +struct S2 { + int S2::*foo; +}; +int S2::*bar; + +template +struct S3 { + int T::*foo; +};