From: Peter Collingbourne Date: Wed, 30 May 2018 03:40:04 +0000 (+0000) Subject: Sema: Add a flag for rejecting member pointers with incomplete base types. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7a3b3665c7782ff7a4a7468a60201227587b4774;p=clang Sema: Add a flag for rejecting member pointers with incomplete base types. Codebases that need to be compatible with the Microsoft ABI can pass this flag to avoid issues caused by the lack of a fixed ABI for incomplete member pointers. Differential Revision: https://reviews.llvm.org/D47503 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@333498 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1fa66cbcfc..b4d76ba918 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6350,6 +6350,8 @@ def err_bad_memptr_rhs : Error< 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; diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def index 654b755f67..8605286f28 100644 --- a/include/clang/Basic/LangOptions.def +++ b/include/clang/Basic/LangOptions.def @@ -247,6 +247,10 @@ ENUM_LANGOPT(AddressSpaceMapMangling , AddrSpaceMapMangling, 2, ASMM_Target, "Op 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, diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index bc27844b72..ed255c97ab 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -782,6 +782,12 @@ def fcomment_block_commands : CommaJoined<["-"], "fcomment-block-commands=">, Gr 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; diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 2c0fc4e7e3..2347cfebf0 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -4784,6 +4784,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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 && diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 75d6a26cdb..594164332e 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -2754,6 +2754,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, << A->getAsString(Args) << A->getValue(); } } + + Opts.CompleteMemberPointers = Args.hasArg(OPT_fcomplete_member_pointers); } static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 7e8f9b19e3..b5a90af39b 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -7585,11 +7585,17 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // 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()); } diff --git a/test/Driver/complete-member-pointers.cpp b/test/Driver/complete-member-pointers.cpp new file mode 100644 index 0000000000..6fde2e7a0e --- /dev/null +++ b/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" diff --git a/test/SemaCXX/complete-member-pointers.cpp b/test/SemaCXX/complete-member-pointers.cpp new file mode 100644 index 0000000000..942bb703a9 --- /dev/null +++ b/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; +};