diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -98,6 +98,8 @@ "Objective-C auto-synthesized properties") BENIGN_LANGOPT(EncodeExtendedBlockSig , 1, 0, "Encoding extended block type signature") +BENIGN_LANGOPT(EncodeCXXClassTemplateSpec , 1, 0, + "Fully encode c++ class template specialization") BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1, "Objective-C related result type inference") LANGOPT(AppExt , 1, 0, "Objective-C App Extension") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2104,6 +2104,13 @@ def fobjc_arc : Flag<["-"], "fobjc-arc">, Group, Flags<[CC1Option]>, HelpText<"Synthesize retain and release calls for Objective-C pointers">; def fno_objc_arc : Flag<["-"], "fno-objc-arc">, Group; +def fobjc_encode_cxx_class_template_spec : + Flag<["-"], "fobjc-encode-cxx-class-template-spec">, Group, + Flags<[CC1Option]>, + HelpText<"Fully encode c++ class template specialization">, + MarshallingInfoFlag>; +def fno_objc_encode_cxx_class_template_spec : + Flag<["-"], "fno-objc-encode-cxx-class-template-spec">, Group; defm objc_convert_messages_to_runtime_calls : BoolFOption<"objc-convert-messages-to-runtime-calls", CodeGenOpts<"ObjCConvertMessagesToRuntimeCalls">, DefaultTrue, NegFlag, PosFlag>; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -7305,6 +7305,40 @@ S += llvm::utostr(FD->getBitWidthValue(*Ctx)); } +// Helper function for determining whether the encoded type string would include +// a template specialization type. +static bool hasTemplateSpecializationInEncodedString(const Type *T, + bool VisitBasesAndFields) { + T = T->getBaseElementTypeUnsafe(); + + if (auto *PT = T->getAs()) + return hasTemplateSpecializationInEncodedString( + PT->getPointeeType().getTypePtr(), false); + + auto *CXXRD = T->getAsCXXRecordDecl(); + + if (!CXXRD) + return false; + + if (isa(CXXRD)) + return true; + + if (!CXXRD->hasDefinition() || !VisitBasesAndFields) + return false; + + for (auto B : CXXRD->bases()) + if (hasTemplateSpecializationInEncodedString(B.getType().getTypePtr(), + true)) + return true; + + for (auto *FD : CXXRD->fields()) + if (hasTemplateSpecializationInEncodedString(FD->getType().getTypePtr(), + true)) + return true; + + return false; +} + // FIXME: Use SmallString for accumulating string. void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, const ObjCEncOptions Options, @@ -7397,6 +7431,15 @@ S += '@'; return; } + // If the encoded string for the class includes template names, just emit + // "^v" for pointers to the class. + if (getLangOpts().CPlusPlus && + (!getLangOpts().EncodeCXXClassTemplateSpec && + hasTemplateSpecializationInEncodedString( + RTy, Options.ExpandPointedToStructures()))) { + S += "^v"; + return; + } // fall through... } S += '^'; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5778,6 +5778,12 @@ if (TC.IsEncodeExtendedBlockSignatureDefault()) CmdArgs.push_back("-fencode-extended-block-signature"); + if (types::isObjC(Input.getType()) && + Args.hasFlag(options::OPT_fobjc_encode_cxx_class_template_spec, + options::OPT_fno_objc_encode_cxx_class_template_spec, + !Triple.isOSDarwin())) + CmdArgs.push_back("-fobjc-encode-cxx-class-template-spec"); + if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts, false) && types::isCXX(InputType)) { diff --git a/clang/test/CodeGenObjCXX/encode.mm b/clang/test/CodeGenObjCXX/encode.mm --- a/clang/test/CodeGenObjCXX/encode.mm +++ b/clang/test/CodeGenObjCXX/encode.mm @@ -1,5 +1,6 @@ -// RUN: %clang_cc1 -Wno-objc-root-class -std=gnu++98 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck --check-prefixes CHECK,CHECKCXX98 %s -// RUN: %clang_cc1 -Wno-objc-root-class -std=gnu++20 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck --check-prefixes CHECK,CHECKCXX20 %s +// RUN: %clang_cc1 -Wno-objc-root-class -std=gnu++98 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck --check-prefixes CHECK,CHECKCXX98,CHECK-NO-TEMP-SPEC %s +// RUN: %clang_cc1 -Wno-objc-root-class -std=gnu++20 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck --check-prefixes CHECK,CHECKCXX20,CHECK-NO-TEMP-SPEC %s +// RUN: %clang_cc1 -Wno-objc-root-class -std=gnu++20 %s -triple=x86_64-apple-darwin10 -fobjc-encode-cxx-class-template-spec -emit-llvm -o - | FileCheck --check-prefixes CHECK,CHECKCXX20,CHECK-TEMP-SPEC %s // CHECK: v17@0:8{vector=}16 // CHECK: {vector=} @@ -260,3 +261,63 @@ extern const char x[] = @encode(I); } #endif + +namespace test_cxx_template_specialization { +template +struct B0 { + T a; +}; +struct D0 : B0 {}; +struct D1 : D0 {}; +struct D2 : virtual B0 {}; +struct S0 { + B0 a; +}; +struct S1 { + B0 *a; +}; +struct S2 { + S1 *a; +}; +template +union U0 { + T a; +}; +typedef B0 TD0; +typedef B0 *Array0[4]; + +// CHECK: @[[STR22:.*]] = {{.*}} [12 x i8] c"{B0=i}\00" +// CHECK: @_ZN32test_cxx_template_specialization2b0E = {{.*}} ([12 x i8], [12 x i8]* @[[STR22]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @[[STR23:.*]] = {{.*}} [3 x i8] c"^v\00" +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization3b01E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-TEMP-SPEC: @[[STR23:.*]] = {{.*}} [13 x i8] c"^{B0=i}\00" +// CHECK-TEMP-SPEC: @_ZN32test_cxx_template_specialization3b01E = {{.*}} ([13 x i8], [13 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization3b02E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization2d0E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization2d1E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization2d2E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK: @[[STR24:.*]] = {{.*}} [7 x i8] c"^^{D2}\00" +// CHECK: @_ZN32test_cxx_template_specialization3d21E = {{.*}} ([7 x i8], [7 x i8]* @[[STR24]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization2s0E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization2s1E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK: @[[STR25:.*]] = {{.*}} [12 x i8] c"^{S2=^{S1}}\00" +// CHECK: @_ZN32test_cxx_template_specialization2s2E = {{.*}} ([12 x i8], [12 x i8]* @[[STR25]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization2u0E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization3td0E = {{.*}} ([3 x i8], [3 x i8]* @[[STR23]], i32 0, i32 0) +// CHECK-NO-TEMP-SPEC: @[[STR26:.*]] = {{.*}} [6 x i8] c"[4^v]\00" +// CHECK-NO-TEMP-SPEC: @_ZN32test_cxx_template_specialization2a0E = {{.*}} ([6 x i8], [6 x i8]* @[[STR26]], i32 0, i32 0) + +const char *b0 = @encode(B0); +const char *b01 = @encode(B0 *); +const char *b02 = @encode(B0 &); +const char *d0 = @encode(D0 *); +const char *d1 = @encode(D1 *); +const char *d2 = @encode(D2 *); +const char *d21 = @encode(D2 **); +const char *s0 = @encode(S0 *); +const char *s1 = @encode(S1 *); +const char *s2 = @encode(S2 *); +const char *u0 = @encode(U0 *); +const char *td0 = @encode(TD0 *); +const char *a0 = @encode(Array0); +} diff --git a/clang/test/Driver/objc-encode-cxx-class-template-spec.m b/clang/test/Driver/objc-encode-cxx-class-template-spec.m new file mode 100644 --- /dev/null +++ b/clang/test/Driver/objc-encode-cxx-class-template-spec.m @@ -0,0 +1,7 @@ +// RUN: %clang -target arm64-apple-ios11 -### %s -o - 2>&1 | FileCheck -check-prefix=DISABLE-ENC %s +// RUN: %clang -target arm64-apple-ios11 -fobjc-encode-cxx-class-template-spec -### %s -o - 2>&1 | FileCheck -check-prefix=ENABLE-ENC %s +// RUN: %clang -target x86_64-linux-gnu -fobjc-runtime=gnustep -### %s -o - 2>&1 | FileCheck -check-prefix=ENABLE-ENC %s +// RUN: %clang -target x86_64-linux-gnu -fobjc-runtime=gnustep -fno-objc-encode-cxx-class-template-spec -### %s -o - 2>&1 | FileCheck -check-prefix=DISABLE-ENC %s + +// DISABLE-ENC-NOT: -fobjc-encode-cxx-class-template-spec +// ENABLE-ENC: -fobjc-encode-cxx-class-template-spec