diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -5084,7 +5084,7 @@ used for call site debug info. The ``retainedNodes:`` field is a list of :ref:`variables ` and :ref:`labels ` that must be retained, even if their IR counterparts are optimized out of the IR. The -``type:`` field must point at an :ref:`DISubroutineType`. +``type:`` field is required and must point at a :ref:`DISubroutineType`. .. _DISubprogramDeclaration: diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1189,8 +1189,9 @@ AssertDI(isa(F), "invalid file", &N, F); else AssertDI(N.getLine() == 0, "line specified with no file", &N, N.getLine()); - if (auto *T = N.getRawType()) - AssertDI(isa(T), "invalid subroutine type", &N, T); + auto *T = N.getRawType(); + AssertDI(T, "subprogram must have a type", &N, T); + AssertDI(isa(T), "invalid subroutine type", &N, T); AssertDI(isType(N.getRawContainingType()), "invalid containing type", &N, N.getRawContainingType()); if (auto *Params = N.getRawTemplateParams()) diff --git a/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll b/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll --- a/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll +++ b/llvm/test/DebugInfo/Generic/verifier-invalid-disubprogram.ll @@ -5,75 +5,80 @@ !0 = distinct !DICompileUnit(language: 0, file: !1) !1 = !DIFile(filename: "-", directory: "") !2 = !{i32 2, !"Debug Info Version", i32 3} +!3 = !DISubroutineType(types: !{null}) ; CHECK: invalid file -define void @invalid_file() !dbg !3 { ret void } -!3 = distinct !DISubprogram(file: !0) +define void @invalid_file() !dbg !4 { ret void } +!4 = distinct !DISubprogram(file: !0) ; CHECK: line specified with no file -define void @line_specified_with_no_file() !dbg !4 { ret void } -!4 = distinct !DISubprogram(line: 1) +define void @line_specified_with_no_file() !dbg !5 { ret void } +!5 = distinct !DISubprogram(line: 1) + +; CHECK: subprogram must have a type +define void @subprogram_must_have_a_type() !dbg !6 { ret void } +!6 = distinct !DISubprogram() ; CHECK: invalid subroutine type -define void @invalid_subroutine_type() !dbg !5 { ret void } -!5 = distinct !DISubprogram(type: !0) +define void @invalid_subroutine_type() !dbg !7 { ret void } +!7 = distinct !DISubprogram(type: !0) ; CHECK: invalid containing type -define void @invalid_containing_type() !dbg !6 { ret void } -!6 = distinct !DISubprogram(containingType: !0) +define void @invalid_containing_type() !dbg !8 { ret void } +!8 = distinct !DISubprogram(type: !3, containingType: !0) ; CHECK: invalid template params -define void @invalid_template_params() !dbg !7 { ret void } -!7 = distinct !DISubprogram(templateParams: !0) +define void @invalid_template_params() !dbg !9 { ret void } +!9 = distinct !DISubprogram(type: !3, templateParams: !0) ; CHECK: invalid template parameter -define void @invalid_template_parameter() !dbg !8 { ret void } -!8 = distinct !DISubprogram(templateParams: !{!0}) +define void @invalid_template_parameter() !dbg !10 { ret void } +!10 = distinct !DISubprogram(type: !3, templateParams: !{!0}) ; CHECK: invalid subprogram declaration -define void @invalid_subprogram_declaration() !dbg !9 { ret void } -!9 = distinct !DISubprogram(declaration: !0) +define void @invalid_subprogram_declaration() !dbg !11 { ret void } +!11 = distinct !DISubprogram(type: !3, declaration: !0) ; CHECK: invalid retained nodes list -define void @invalid_retained_nodes_list() !dbg !10 { ret void } -!10 = distinct !DISubprogram(retainedNodes: !0) +define void @invalid_retained_nodes_list() !dbg !12 { ret void } +!12 = distinct !DISubprogram(type: !3, retainedNodes: !0) ; CHECK: invalid retained nodes, expected DILocalVariable or DILabel -define void @invalid_retained_nodes_expected() !dbg !11 { ret void } -!11 = distinct !DISubprogram(retainedNodes: !{!0}) +define void @invalid_retained_nodes_expected() !dbg !13 { ret void } +!13 = distinct !DISubprogram(type: !3, retainedNodes: !{!0}) ; CHECK: invalid reference flags -define void @invalid_reference_flags_reference() !dbg !12 { ret void } -!12 = distinct !DISubprogram(flags: DIFlagLValueReference | DIFlagRValueReference) +define void @invalid_reference_flags_reference() !dbg !14 { ret void } +!14 = distinct !DISubprogram(type: !3, flags: DIFlagLValueReference | DIFlagRValueReference) ; CHECK: invalid reference flags -define void @invalid_reference_flags_pass_by() !dbg !13 { ret void } -!13 = distinct !DISubprogram(flags: DIFlagTypePassByValue | DIFlagTypePassByReference) +define void @invalid_reference_flags_pass_by() !dbg !15 { ret void } +!15 = distinct !DISubprogram(type: !3, flags: DIFlagTypePassByValue | DIFlagTypePassByReference) ; CHECK: subprogram definitions must have a compile unit -define void @subprogram_definitions_must_have_a_compile_unit() !dbg !14 { ret void } -!14 = distinct !DISubprogram() +define void @subprogram_definitions_must_have_a_compile_unit() !dbg !16 { ret void } +!16 = distinct !DISubprogram(type: !3) ; CHECK: invalid unit type -define void @invalid_unit_type() !dbg !15 { ret void } -!15 = distinct !DISubprogram(unit: !{}) +define void @invalid_unit_type() !dbg !17 { ret void } +!17 = distinct !DISubprogram(type: !3, unit: !{}) ; FIXME: should something verify `isDefinition` is not a lie? is it meaningful ; to mistmatch it with respect to the LLVM IR function? ; CHECK: subprogram declarations must not have a compile unit -define void @subprogram_declarations_must_not_have_a_compile_unit() !dbg !16 { ret void } -!16 = distinct !DISubprogram(isDefinition: false, unit: !0) +define void @subprogram_declarations_must_not_have_a_compile_unit() !dbg !18 { ret void } +!18 = distinct !DISubprogram(type: !3, isDefinition: false, unit: !0) ; CHECK: invalid thrown types list -define void @invalid_thrown_types_list() !dbg !17 { ret void } -!17 = distinct !DISubprogram(isDefinition: false, thrownTypes: !0) +define void @invalid_thrown_types_list() !dbg !19 { ret void } +!19 = distinct !DISubprogram(type: !3, isDefinition: false, thrownTypes: !0) ; CHECK: invalid thrown type -define void @invalid_thrown_type() !dbg !18 { ret void } -!18 = distinct !DISubprogram(isDefinition: false, thrownTypes: !{!0}) +define void @invalid_thrown_type() !dbg !20 { ret void } +!20 = distinct !DISubprogram(type: !3, isDefinition: false, thrownTypes: !{!0}) ; CHECK: DIFlagAllCallsDescribed must be attached to a definition -define void @DIFlagAllCallsDescribed_must_be_attached_to_a_definition() !dbg !19 { ret void } -!19 = distinct !DISubprogram(isDefinition: false, flags: DIFlagAllCallsDescribed) +define void @DIFlagAllCallsDescribed_must_be_attached_to_a_definition() !dbg !21 { ret void } +!21 = distinct !DISubprogram(type: !3, isDefinition: false, flags: DIFlagAllCallsDescribed) ; CHECK: warning: ignoring invalid debug info{{.*}}