From 6acc789ad3f6c04319764f414ebb1a08e6145332 Mon Sep 17 00:00:00 2001 From: Taras Madan Date: Wed, 5 Jan 2022 15:28:35 +0100 Subject: dashboard/app: update to go116 (#2959) 1. Updated the "include"s. 2. No logs read API in the AppEngine anymore. Replaced by the GCP logging API. 3. Use "GO111MODULE=off gcloud beta app deploy ./dashboard/app/app.yaml --no-promote" to test new deployment. 4. Updated the documentation. --- .../github.com/golang/protobuf/proto/registry.go | 10 +- .../golang/protobuf/proto/text_decode.go | 2 +- vendor/github.com/golang/protobuf/ptypes/any.go | 14 + vendor/github.com/golang/protobuf/ptypes/doc.go | 4 + .../github.com/golang/protobuf/ptypes/duration.go | 4 + .../golang/protobuf/ptypes/struct/struct.pb.go | 78 ++++ .../github.com/golang/protobuf/ptypes/timestamp.go | 9 + .../github.com/google/go-cmp/cmp/report_compare.go | 4 +- .../github.com/google/go-cmp/cmp/report_slices.go | 25 +- vendor/github.com/ianlancetaylor/demangle/ast.go | 378 ++++++++++++++-- .../github.com/ianlancetaylor/demangle/demangle.go | 502 +++++++++++++++++---- 11 files changed, 893 insertions(+), 137 deletions(-) create mode 100644 vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go (limited to 'vendor/github.com') diff --git a/vendor/github.com/golang/protobuf/proto/registry.go b/vendor/github.com/golang/protobuf/proto/registry.go index 1e7ff6420..066b4323b 100644 --- a/vendor/github.com/golang/protobuf/proto/registry.go +++ b/vendor/github.com/golang/protobuf/proto/registry.go @@ -13,6 +13,7 @@ import ( "strings" "sync" + "google.golang.org/protobuf/reflect/protodesc" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" "google.golang.org/protobuf/runtime/protoimpl" @@ -62,14 +63,7 @@ func FileDescriptor(s filePath) fileDescGZIP { // Find the descriptor in the v2 registry. var b []byte if fd, _ := protoregistry.GlobalFiles.FindFileByPath(s); fd != nil { - if fd, ok := fd.(interface{ ProtoLegacyRawDesc() []byte }); ok { - b = fd.ProtoLegacyRawDesc() - } else { - // TODO: Use protodesc.ToFileDescriptorProto to construct - // a descriptorpb.FileDescriptorProto and marshal it. - // However, doing so causes the proto package to have a dependency - // on descriptorpb, leading to cyclic dependency issues. - } + b, _ = Marshal(protodesc.ToFileDescriptorProto(fd)) } // Locally cache the raw descriptor form for the file. diff --git a/vendor/github.com/golang/protobuf/proto/text_decode.go b/vendor/github.com/golang/protobuf/proto/text_decode.go index 4a5931009..47eb3e445 100644 --- a/vendor/github.com/golang/protobuf/proto/text_decode.go +++ b/vendor/github.com/golang/protobuf/proto/text_decode.go @@ -765,7 +765,7 @@ func unescape(s string) (ch string, tail string, err error) { if i > utf8.MaxRune { return "", "", fmt.Errorf(`\%c%s is not a valid Unicode code point`, r, ss) } - return string(i), s, nil + return string(rune(i)), s, nil } return "", "", fmt.Errorf(`unknown escape \%c`, r) } diff --git a/vendor/github.com/golang/protobuf/ptypes/any.go b/vendor/github.com/golang/protobuf/ptypes/any.go index e729dcff1..85f9f5736 100644 --- a/vendor/github.com/golang/protobuf/ptypes/any.go +++ b/vendor/github.com/golang/protobuf/ptypes/any.go @@ -19,6 +19,8 @@ const urlPrefix = "type.googleapis.com/" // AnyMessageName returns the message name contained in an anypb.Any message. // Most type assertions should use the Is function instead. +// +// Deprecated: Call the any.MessageName method instead. func AnyMessageName(any *anypb.Any) (string, error) { name, err := anyMessageName(any) return string(name), err @@ -38,6 +40,8 @@ func anyMessageName(any *anypb.Any) (protoreflect.FullName, error) { } // MarshalAny marshals the given message m into an anypb.Any message. +// +// Deprecated: Call the anypb.New function instead. func MarshalAny(m proto.Message) (*anypb.Any, error) { switch dm := m.(type) { case DynamicAny: @@ -58,6 +62,9 @@ func MarshalAny(m proto.Message) (*anypb.Any, error) { // Empty returns a new message of the type specified in an anypb.Any message. // It returns protoregistry.NotFound if the corresponding message type could not // be resolved in the global registry. +// +// Deprecated: Use protoregistry.GlobalTypes.FindMessageByName instead +// to resolve the message name and create a new instance of it. func Empty(any *anypb.Any) (proto.Message, error) { name, err := anyMessageName(any) if err != nil { @@ -76,6 +83,8 @@ func Empty(any *anypb.Any) (proto.Message, error) { // // The target message m may be a *DynamicAny message. If the underlying message // type could not be resolved, then this returns protoregistry.NotFound. +// +// Deprecated: Call the any.UnmarshalTo method instead. func UnmarshalAny(any *anypb.Any, m proto.Message) error { if dm, ok := m.(*DynamicAny); ok { if dm.Message == nil { @@ -100,6 +109,8 @@ func UnmarshalAny(any *anypb.Any, m proto.Message) error { } // Is reports whether the Any message contains a message of the specified type. +// +// Deprecated: Call the any.MessageIs method instead. func Is(any *anypb.Any, m proto.Message) bool { if any == nil || m == nil { return false @@ -119,6 +130,9 @@ func Is(any *anypb.Any, m proto.Message) bool { // var x ptypes.DynamicAny // if err := ptypes.UnmarshalAny(a, &x); err != nil { ... } // fmt.Printf("unmarshaled message: %v", x.Message) +// +// Deprecated: Use the any.UnmarshalNew method instead to unmarshal +// the any message contents into a new instance of the underlying message. type DynamicAny struct{ proto.Message } func (m DynamicAny) String() string { diff --git a/vendor/github.com/golang/protobuf/ptypes/doc.go b/vendor/github.com/golang/protobuf/ptypes/doc.go index fb9edd5c6..d3c33259d 100644 --- a/vendor/github.com/golang/protobuf/ptypes/doc.go +++ b/vendor/github.com/golang/protobuf/ptypes/doc.go @@ -3,4 +3,8 @@ // license that can be found in the LICENSE file. // Package ptypes provides functionality for interacting with well-known types. +// +// Deprecated: Well-known types have specialized functionality directly +// injected into the generated packages for each message type. +// See the deprecation notice for each function for the suggested alternative. package ptypes diff --git a/vendor/github.com/golang/protobuf/ptypes/duration.go b/vendor/github.com/golang/protobuf/ptypes/duration.go index 6110ae8a4..b2b55dd85 100644 --- a/vendor/github.com/golang/protobuf/ptypes/duration.go +++ b/vendor/github.com/golang/protobuf/ptypes/duration.go @@ -21,6 +21,8 @@ const ( // Duration converts a durationpb.Duration to a time.Duration. // Duration returns an error if dur is invalid or overflows a time.Duration. +// +// Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead. func Duration(dur *durationpb.Duration) (time.Duration, error) { if err := validateDuration(dur); err != nil { return 0, err @@ -39,6 +41,8 @@ func Duration(dur *durationpb.Duration) (time.Duration, error) { } // DurationProto converts a time.Duration to a durationpb.Duration. +// +// Deprecated: Call the durationpb.New function instead. func DurationProto(d time.Duration) *durationpb.Duration { nanos := d.Nanoseconds() secs := nanos / 1e9 diff --git a/vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go b/vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go new file mode 100644 index 000000000..8d82abe21 --- /dev/null +++ b/vendor/github.com/golang/protobuf/ptypes/struct/struct.pb.go @@ -0,0 +1,78 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: github.com/golang/protobuf/ptypes/struct/struct.proto + +package structpb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" +) + +// Symbols defined in public import of google/protobuf/struct.proto. + +type NullValue = structpb.NullValue + +const NullValue_NULL_VALUE = structpb.NullValue_NULL_VALUE + +var NullValue_name = structpb.NullValue_name +var NullValue_value = structpb.NullValue_value + +type Struct = structpb.Struct +type Value = structpb.Value +type Value_NullValue = structpb.Value_NullValue +type Value_NumberValue = structpb.Value_NumberValue +type Value_StringValue = structpb.Value_StringValue +type Value_BoolValue = structpb.Value_BoolValue +type Value_StructValue = structpb.Value_StructValue +type Value_ListValue = structpb.Value_ListValue +type ListValue = structpb.ListValue + +var File_github_com_golang_protobuf_ptypes_struct_struct_proto protoreflect.FileDescriptor + +var file_github_com_golang_protobuf_ptypes_struct_struct_proto_rawDesc = []byte{ + 0x0a, 0x35, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, + 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, + 0x70, 0x65, 0x73, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x42, 0x33, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x70, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x3b, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x70, 0x62, 0x50, 0x00, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var file_github_com_golang_protobuf_ptypes_struct_struct_proto_goTypes = []interface{}{} +var file_github_com_golang_protobuf_ptypes_struct_struct_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_github_com_golang_protobuf_ptypes_struct_struct_proto_init() } +func file_github_com_golang_protobuf_ptypes_struct_struct_proto_init() { + if File_github_com_golang_protobuf_ptypes_struct_struct_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_github_com_golang_protobuf_ptypes_struct_struct_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_github_com_golang_protobuf_ptypes_struct_struct_proto_goTypes, + DependencyIndexes: file_github_com_golang_protobuf_ptypes_struct_struct_proto_depIdxs, + }.Build() + File_github_com_golang_protobuf_ptypes_struct_struct_proto = out.File + file_github_com_golang_protobuf_ptypes_struct_struct_proto_rawDesc = nil + file_github_com_golang_protobuf_ptypes_struct_struct_proto_goTypes = nil + file_github_com_golang_protobuf_ptypes_struct_struct_proto_depIdxs = nil +} diff --git a/vendor/github.com/golang/protobuf/ptypes/timestamp.go b/vendor/github.com/golang/protobuf/ptypes/timestamp.go index 026d0d491..8368a3f70 100644 --- a/vendor/github.com/golang/protobuf/ptypes/timestamp.go +++ b/vendor/github.com/golang/protobuf/ptypes/timestamp.go @@ -33,6 +33,8 @@ const ( // // A nil Timestamp returns an error. The first return value in that case is // undefined. +// +// Deprecated: Call the ts.AsTime and ts.CheckValid methods instead. func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) { // Don't return the zero value on error, because corresponds to a valid // timestamp. Instead return whatever time.Unix gives us. @@ -46,6 +48,8 @@ func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) { } // TimestampNow returns a google.protobuf.Timestamp for the current time. +// +// Deprecated: Call the timestamppb.Now function instead. func TimestampNow() *timestamppb.Timestamp { ts, err := TimestampProto(time.Now()) if err != nil { @@ -56,6 +60,8 @@ func TimestampNow() *timestamppb.Timestamp { // TimestampProto converts the time.Time to a google.protobuf.Timestamp proto. // It returns an error if the resulting Timestamp is invalid. +// +// Deprecated: Call the timestamppb.New function instead. func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) { ts := ×tamppb.Timestamp{ Seconds: t.Unix(), @@ -69,6 +75,9 @@ func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) { // TimestampString returns the RFC 3339 string for valid Timestamps. // For invalid Timestamps, it returns an error message in parentheses. +// +// Deprecated: Call the ts.AsTime method instead, +// followed by a call to the Format method on the time.Time value. func TimestampString(ts *timestamppb.Timestamp) string { t, err := Timestamp(ts) if err != nil { diff --git a/vendor/github.com/google/go-cmp/cmp/report_compare.go b/vendor/github.com/google/go-cmp/cmp/report_compare.go index a6c070cfc..104bb3053 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_compare.go +++ b/vendor/github.com/google/go-cmp/cmp/report_compare.go @@ -79,7 +79,7 @@ func (opts formatOptions) verbosity() uint { } } -const maxVerbosityPreset = 3 +const maxVerbosityPreset = 6 // verbosityPreset modifies the verbosity settings given an index // between 0 and maxVerbosityPreset, inclusive. @@ -100,7 +100,7 @@ func verbosityPreset(opts formatOptions, i int) formatOptions { func (opts formatOptions) FormatDiff(v *valueNode, ptrs *pointerReferences) (out textNode) { if opts.DiffMode == diffIdentical { opts = opts.WithVerbosity(1) - } else { + } else if opts.verbosity() < 3 { opts = opts.WithVerbosity(3) } diff --git a/vendor/github.com/google/go-cmp/cmp/report_slices.go b/vendor/github.com/google/go-cmp/cmp/report_slices.go index da04caf16..168f92f3c 100644 --- a/vendor/github.com/google/go-cmp/cmp/report_slices.go +++ b/vendor/github.com/google/go-cmp/cmp/report_slices.go @@ -26,8 +26,6 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { return false // No differences detected case !v.ValueX.IsValid() || !v.ValueY.IsValid(): return false // Both values must be valid - case v.Type.Kind() == reflect.Slice && (v.ValueX.Len() == 0 || v.ValueY.Len() == 0): - return false // Both slice values have to be non-empty case v.NumIgnored > 0: return false // Some ignore option was used case v.NumTransformed > 0: @@ -45,7 +43,16 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { return false } - switch t := v.Type; t.Kind() { + // Check whether this is an interface with the same concrete types. + t := v.Type + vx, vy := v.ValueX, v.ValueY + if t.Kind() == reflect.Interface && !vx.IsNil() && !vy.IsNil() && vx.Elem().Type() == vy.Elem().Type() { + vx, vy = vx.Elem(), vy.Elem() + t = vx.Type() + } + + // Check whether we provide specialized diffing for this type. + switch t.Kind() { case reflect.String: case reflect.Array, reflect.Slice: // Only slices of primitive types have specialized handling. @@ -57,6 +64,11 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { return false } + // Both slice values have to be non-empty. + if t.Kind() == reflect.Slice && (vx.Len() == 0 || vy.Len() == 0) { + return false + } + // If a sufficient number of elements already differ, // use specialized formatting even if length requirement is not met. if v.NumDiff > v.NumSame { @@ -68,7 +80,7 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { // Use specialized string diffing for longer slices or strings. const minLength = 64 - return v.ValueX.Len() >= minLength && v.ValueY.Len() >= minLength + return vx.Len() >= minLength && vy.Len() >= minLength } // FormatDiffSlice prints a diff for the slices (or strings) represented by v. @@ -77,6 +89,11 @@ func (opts formatOptions) CanFormatDiffSlice(v *valueNode) bool { func (opts formatOptions) FormatDiffSlice(v *valueNode) textNode { assert(opts.DiffMode == diffUnknown) t, vx, vy := v.Type, v.ValueX, v.ValueY + if t.Kind() == reflect.Interface { + vx, vy = vx.Elem(), vy.Elem() + t = vx.Type() + opts = opts.WithTypeMode(emitType) + } // Auto-detect the type of the data. var isLinedText, isText, isBinary bool diff --git a/vendor/github.com/ianlancetaylor/demangle/ast.go b/vendor/github.com/ianlancetaylor/demangle/ast.go index 0ad5354f5..ccbe5b355 100644 --- a/vendor/github.com/ianlancetaylor/demangle/ast.go +++ b/vendor/github.com/ianlancetaylor/demangle/ast.go @@ -5,7 +5,6 @@ package demangle import ( - "bytes" "fmt" "strings" ) @@ -23,7 +22,10 @@ type AST interface { // Copy an AST with possible transformations. // If the skip function returns true, no copy is required. // If the copy function returns nil, no copy is required. - // Otherwise the AST returned by copy is used in a copy of the full AST. + // The Copy method will do the right thing if copy returns nil + // for some components of an AST but not others, so a good + // copy function will only return non-nil for AST values that + // need to change. // Copy itself returns either a copy or nil. Copy(copy func(AST) AST, skip func(AST) bool) AST @@ -51,7 +53,7 @@ func ASTToString(a AST, options ...Option) string { type printState struct { tparams bool // whether to print template parameters - buf bytes.Buffer + buf strings.Builder last byte // Last byte written to buffer. // The inner field is a list of items to print for a type @@ -398,13 +400,172 @@ func (tp *TemplateParam) goString(indent int, field string) string { return fmt.Sprintf("%*s%sTemplateParam: Template: %p; Index %d", indent, "", field, tp.Template, tp.Index) } +// LambdaAuto is a lambda auto parameter. +type LambdaAuto struct { + Index int +} + +func (la *LambdaAuto) print(ps *printState) { + // We print the index plus 1 because that is what the standard + // demangler does. + fmt.Fprintf(&ps.buf, "auto:%d", la.Index+1) +} + +func (la *LambdaAuto) Traverse(fn func(AST) bool) { + fn(la) +} + +func (la *LambdaAuto) Copy(fn func(AST) AST, skip func(AST) bool) AST { + if skip(la) { + return nil + } + return fn(la) +} + +func (la *LambdaAuto) GoString() string { + return la.goString(0, "") +} + +func (la *LambdaAuto) goString(indent int, field string) string { + return fmt.Sprintf("%*s%sLambdaAuto: Index %d", indent, "", field, la.Index) +} + // Qualifiers is an ordered list of type qualifiers. -type Qualifiers []string +type Qualifiers struct { + Qualifiers []AST +} + +func (qs *Qualifiers) print(ps *printState) { + first := true + for _, q := range qs.Qualifiers { + if !first { + ps.writeByte(' ') + } + q.print(ps) + first = false + } +} + +func (qs *Qualifiers) Traverse(fn func(AST) bool) { + if fn(qs) { + for _, q := range qs.Qualifiers { + q.Traverse(fn) + } + } +} + +func (qs *Qualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST { + if skip(qs) { + return nil + } + changed := false + qualifiers := make([]AST, len(qs.Qualifiers)) + for i, q := range qs.Qualifiers { + qc := q.Copy(fn, skip) + if qc == nil { + qualifiers[i] = q + } else { + qualifiers[i] = qc + changed = true + } + } + if !changed { + return fn(qs) + } + qs = &Qualifiers{Qualifiers: qualifiers} + if r := fn(qs); r != nil { + return r + } + return qs +} + +func (qs *Qualifiers) GoString() string { + return qs.goString(0, "") +} + +func (qs *Qualifiers) goString(indent int, field string) string { + quals := fmt.Sprintf("%*s%s", indent, "", field) + for _, q := range qs.Qualifiers { + quals += "\n" + quals += q.goString(indent+2, "") + } + return quals +} + +// Qualifier is a single type qualifier. +type Qualifier struct { + Name string // qualifier name: const, volatile, etc. + Exprs []AST // can be non-nil for noexcept and throw +} + +func (q *Qualifier) print(ps *printState) { + ps.writeString(q.Name) + if len(q.Exprs) > 0 { + ps.writeByte('(') + first := true + for _, e := range q.Exprs { + if !first { + ps.writeString(", ") + } + ps.print(e) + first = false + } + ps.writeByte(')') + } +} + +func (q *Qualifier) Traverse(fn func(AST) bool) { + if fn(q) { + for _, e := range q.Exprs { + e.Traverse(fn) + } + } +} + +func (q *Qualifier) Copy(fn func(AST) AST, skip func(AST) bool) AST { + if skip(q) { + return nil + } + exprs := make([]AST, len(q.Exprs)) + changed := false + for i, e := range q.Exprs { + ec := e.Copy(fn, skip) + if ec == nil { + exprs[i] = e + } else { + exprs[i] = ec + changed = true + } + } + if !changed { + return fn(q) + } + q = &Qualifier{Name: q.Name, Exprs: exprs} + if r := fn(q); r != nil { + return r + } + return q +} + +func (q *Qualifier) GoString() string { + return q.goString(0, "Qualifier: ") +} + +func (q *Qualifier) goString(indent int, field string) string { + qs := fmt.Sprintf("%*s%s%s", indent, "", field, q.Name) + if len(q.Exprs) > 0 { + for i, e := range q.Exprs { + qs += "\n" + qs += e.goString(indent+2, fmt.Sprintf("%d: ", i)) + } + } + return qs +} // TypeWithQualifiers is a type with standard qualifiers. type TypeWithQualifiers struct { Base AST - Qualifiers Qualifiers + Qualifiers AST } func (twq *TypeWithQualifiers) print(ps *printState) { @@ -414,7 +575,7 @@ func (twq *TypeWithQualifiers) print(ps *printState) { if len(ps.inner) > 0 { // The qualifier wasn't printed by Base. ps.writeByte(' ') - ps.writeString(strings.Join(twq.Qualifiers, " ")) + ps.print(twq.Qualifiers) ps.inner = ps.inner[:len(ps.inner)-1] } } @@ -422,7 +583,7 @@ func (twq *TypeWithQualifiers) print(ps *printState) { // Print qualifiers as an inner type by just printing the qualifiers. func (twq *TypeWithQualifiers) printInner(ps *printState) { ps.writeByte(' ') - ps.writeString(strings.Join(twq.Qualifiers, " ")) + ps.print(twq.Qualifiers) } func (twq *TypeWithQualifiers) Traverse(fn func(AST) bool) { @@ -436,10 +597,17 @@ func (twq *TypeWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST { return nil } base := twq.Base.Copy(fn, skip) - if base == nil { + quals := twq.Qualifiers.Copy(fn, skip) + if base == nil && quals == nil { return fn(twq) } - twq = &TypeWithQualifiers{Base: base, Qualifiers: twq.Qualifiers} + if base == nil { + base = twq.Base + } + if quals == nil { + quals = twq.Qualifiers + } + twq = &TypeWithQualifiers{Base: base, Qualifiers: quals} if r := fn(twq); r != nil { return r } @@ -451,14 +619,15 @@ func (twq *TypeWithQualifiers) GoString() string { } func (twq *TypeWithQualifiers) goString(indent int, field string) string { - return fmt.Sprintf("%*s%sTypeWithQualifiers: Qualifiers: %s\n%s", indent, "", field, - twq.Qualifiers, twq.Base.goString(indent+2, "Base: ")) + return fmt.Sprintf("%*s%sTypeWithQualifiers:\n%s\n%s", indent, "", field, + twq.Qualifiers.goString(indent+2, "Qualifiers: "), + twq.Base.goString(indent+2, "Base: ")) } // MethodWithQualifiers is a method with qualifiers. type MethodWithQualifiers struct { Method AST - Qualifiers Qualifiers + Qualifiers AST RefQualifier string // "" or "&" or "&&" } @@ -467,9 +636,9 @@ func (mwq *MethodWithQualifiers) print(ps *printState) { ps.inner = append(ps.inner, mwq) ps.print(mwq.Method) if len(ps.inner) > 0 { - if len(mwq.Qualifiers) > 0 { + if mwq.Qualifiers != nil { ps.writeByte(' ') - ps.writeString(strings.Join(mwq.Qualifiers, " ")) + ps.print(mwq.Qualifiers) } if mwq.RefQualifier != "" { ps.writeByte(' ') @@ -480,9 +649,9 @@ func (mwq *MethodWithQualifiers) print(ps *printState) { } func (mwq *MethodWithQualifiers) printInner(ps *printState) { - if len(mwq.Qualifiers) > 0 { + if mwq.Qualifiers != nil { ps.writeByte(' ') - ps.writeString(strings.Join(mwq.Qualifiers, " ")) + ps.print(mwq.Qualifiers) } if mwq.RefQualifier != "" { ps.writeByte(' ') @@ -501,10 +670,20 @@ func (mwq *MethodWithQualifiers) Copy(fn func(AST) AST, skip func(AST) bool) AST return nil } method := mwq.Method.Copy(fn, skip) - if method == nil { + var quals AST + if mwq.Qualifiers != nil { + quals = mwq.Qualifiers.Copy(fn, skip) + } + if method == nil && quals == nil { return fn(mwq) } - mwq = &MethodWithQualifiers{Method: method, Qualifiers: mwq.Qualifiers, RefQualifier: mwq.RefQualifier} + if method == nil { + method = mwq.Method + } + if quals == nil { + quals = mwq.Qualifiers + } + mwq = &MethodWithQualifiers{Method: method, Qualifiers: quals, RefQualifier: mwq.RefQualifier} if r := fn(mwq); r != nil { return r } @@ -517,14 +696,14 @@ func (mwq *MethodWithQualifiers) GoString() string { func (mwq *MethodWithQualifiers) goString(indent int, field string) string { var q string - if len(mwq.Qualifiers) > 0 { - q += fmt.Sprintf(" Qualifiers: %v", mwq.Qualifiers) + if mwq.Qualifiers != nil { + q += "\n" + mwq.Qualifiers.goString(indent+2, "Qualifiers: ") } if mwq.RefQualifier != "" { if q != "" { - q += ";" + q += "\n" } - q += " RefQualifier: " + mwq.RefQualifier + q += fmt.Sprintf("%*s%s%s", indent+2, "", "RefQualifier: ", mwq.RefQualifier) } return fmt.Sprintf("%*s%sMethodWithQualifiers:%s\n%s", indent, "", field, q, mwq.Method.goString(indent+2, "Method: ")) @@ -1955,6 +2134,22 @@ func (u *Unary) goString(indent int, field string) string { u.Expr.goString(indent+2, "Expr: ")) } +// isDesignatedInitializer reports whether x is a designated +// initializer. +func isDesignatedInitializer(x AST) bool { + switch x := x.(type) { + case *Binary: + if op, ok := x.Op.(*Operator); ok { + return op.Name == "=" || op.Name == "]=" + } + case *Trinary: + if op, ok := x.Op.(*Operator); ok { + return op.Name == "[...]=" + } + } + return false +} + // Binary is a binary operation in an expression. type Binary struct { Op AST @@ -1975,6 +2170,27 @@ func (b *Binary) print(ps *printState) { return } + if isDesignatedInitializer(b) { + if op.Name == "=" { + ps.writeByte('.') + } else { + ps.writeByte('[') + } + ps.print(b.Left) + if op.Name == "]=" { + ps.writeByte(']') + } + if isDesignatedInitializer(b.Right) { + // Don't add anything between designated + // initializer chains. + ps.print(b.Right) + } else { + ps.writeByte('=') + parenthesize(ps, b.Right) + } + return + } + // Use an extra set of parentheses around an expression that // uses the greater-than operator, so that it does not get // confused with the '>' that ends template parameters. @@ -1984,15 +2200,28 @@ func (b *Binary) print(ps *printState) { left := b.Left - // A function call in an expression should not print the types - // of the arguments. + // For a function call in an expression, don't print the types + // of the arguments unless there is a return type. + skipParens := false if op != nil && op.Name == "()" { if ty, ok := b.Left.(*Typed); ok { - left = ty.Name + if ft, ok := ty.Type.(*FunctionType); ok { + if ft.Return == nil { + left = ty.Name + } else { + skipParens = true + } + } else { + left = ty.Name + } } } - parenthesize(ps, left) + if skipParens { + ps.print(left) + } else { + parenthesize(ps, left) + } if op != nil && op.Name == "[]" { ps.writeByte('[') @@ -2070,6 +2299,23 @@ type Trinary struct { } func (t *Trinary) print(ps *printState) { + if isDesignatedInitializer(t) { + ps.writeByte('[') + ps.print(t.First) + ps.writeString(" ... ") + ps.print(t.Second) + ps.writeByte(']') + if isDesignatedInitializer(t.Third) { + // Don't add anything between designated + // initializer chains. + ps.print(t.Third) + } else { + ps.writeByte('=') + parenthesize(ps, t.Third) + } + return + } + parenthesize(ps, t.First) ps.writeByte('?') parenthesize(ps, t.Second) @@ -2362,6 +2608,9 @@ func (l *Literal) print(ps *printState) { ps.writeString("true") return } + } else if b.Name == "decltype(nullptr)" && l.Val == "" { + ps.print(l.Type) + return } else { isFloat = builtinTypeFloat[b.Name] } @@ -2821,6 +3070,83 @@ func (s *Special2) goString(indent int, field string) string { indent+2, "", s.Middle, s.Val2.goString(indent+2, "Val2: ")) } +// EnableIf is used by clang for an enable_if attribute. +type EnableIf struct { + Type AST + Args []AST +} + +func (ei *EnableIf) print(ps *printState) { + ps.print(ei.Type) + ps.writeString(" [enable_if:") + first := true + for _, a := range ei.Args { + if !first { + ps.writeString(", ") + } + ps.print(a) + first = false + } + ps.writeString("]") +} + +func (ei *EnableIf) Traverse(fn func(AST) bool) { + if fn(ei) { + ei.Type.Traverse(fn) + for _, a := range ei.Args { + a.Traverse(fn) + } + } +} + +func (ei *EnableIf) Copy(fn func(AST) AST, skip func(AST) bool) AST { + if skip(ei) { + return nil + } + typ := ei.Type.Copy(fn, skip) + argsChanged := false + args := make([]AST, len(ei.Args)) + for i, a := range ei.Args { + ac := a.Copy(fn, skip) + if ac == nil { + args[i] = a + } else { + args[i] = ac + argsChanged = true + } + } + if typ == nil && !argsChanged { + return fn(ei) + } + if typ == nil { + typ = ei.Type + } + ei = &EnableIf{Type: typ, Args: args} + if r := fn(ei); r != nil { + return r + } + return ei +} + +func (ei *EnableIf) GoString() string { + return ei.goString(0, "") +} + +func (ei *EnableIf) goString(indent int, field string) string { + var args string + if len(ei.Args) == 0 { + args = fmt.Sprintf("%*sArgs: nil", indent+2, "") + } else { + args = fmt.Sprintf("%*sArgs:", indent+2, "") + for i, a := range ei.Args { + args += "\n" + args += a.goString(indent+4, fmt.Sprintf("%d: ", i)) + } + } + return fmt.Sprintf("%*s%sEnableIf:\n%s\n%s", indent, "", field, + ei.Type.goString(indent+2, "Type: "), args) +} + // Print the inner types. func (ps *printState) printInner(prefixOnly bool) []AST { var save []AST diff --git a/vendor/github.com/ianlancetaylor/demangle/demangle.go b/vendor/github.com/ianlancetaylor/demangle/demangle.go index 62667bbde..c2667446d 100644 --- a/vendor/github.com/ianlancetaylor/demangle/demangle.go +++ b/vendor/github.com/ianlancetaylor/demangle/demangle.go @@ -5,6 +5,8 @@ // Package demangle defines functions that demangle GCC/LLVM C++ symbol names. // This package recognizes names that were mangled according to the C++ ABI // defined at http://codesourcery.com/cxx-abi/. +// +// Most programs will want to call Filter or ToString. package demangle import ( @@ -45,7 +47,7 @@ func Filter(name string, options ...Option) string { return ret } -// ToString demangles a C++ symbol name, returning human-readable C++ +// ToString demangles a C++ symbol name, returning a human-readable C++ // name or an error. // If the name does not appear to be a C++ symbol name at all, the // error will be ErrNotMangledName. @@ -183,6 +185,7 @@ type state struct { off int // offset of str within original string subs substitutions // substitutions templates []*Template // templates being processed + inLambda int // number of lambdas being parsed } // copy returns a copy of the current state. @@ -250,6 +253,7 @@ func adjustErr(err error, adj int) error { } type forLocalNameType int + const ( forLocalName forLocalNameType = iota notForLocalName @@ -309,15 +313,42 @@ func (st *state) encoding(params bool, local forLocalNameType) AST { if mwq != nil { check = mwq.Method } - template, _ := check.(*Template) + + var template *Template + switch check := check.(type) { + case *Template: + template = check + case *Qualified: + if check.LocalName { + n := check.Name + if nmwq, ok := n.(*MethodWithQualifiers); ok { + n = nmwq.Method + } + template, _ = n.(*Template) + } + } + var oldInLambda int if template != nil { st.templates = append(st.templates, template) + oldInLambda = st.inLambda + st.inLambda = 0 + } + + // Checking for the enable_if attribute here is what the LLVM + // demangler does. This is not very general but perhaps it is + // sufficent. + const enableIfPrefix = "Ua9enable_ifI" + var enableIfArgs []AST + if strings.HasPrefix(st.str, enableIfPrefix) { + st.advance(len(enableIfPrefix) - 1) + enableIfArgs = st.templateArgs() } ft := st.bareFunctionType(hasReturnType(a)) if template != nil { st.templates = st.templates[:len(st.templates)-1] + st.inLambda = oldInLambda } ft = simplify(ft) @@ -348,13 +379,24 @@ func (st *state) encoding(params bool, local forLocalNameType) AST { } } - return &Typed{Name: a, Type: ft} + r := AST(&Typed{Name: a, Type: ft}) + + if len(enableIfArgs) > 0 { + r = &EnableIf{Type: r, Args: enableIfArgs} + } + + return r } // hasReturnType returns whether the mangled form of a will have a // return type. func hasReturnType(a AST) bool { switch a := a.(type) { + case *Qualified: + if a.LocalName { + return hasReturnType(a.Name) + } + return false case *Template: return !isCDtorConversion(a.Name) case *TypeWithQualifiers: @@ -480,7 +522,7 @@ func (st *state) nestedName() AST { q := st.cvQualifiers() r := st.refQualifier() a := st.prefix() - if len(q) > 0 || r != "" { + if q != nil || r != "" { a = &MethodWithQualifiers{Method: a, Qualifiers: q, RefQualifier: r} } if len(st.str) == 0 || st.str[0] != 'E' { @@ -607,6 +649,29 @@ func (st *state) prefix() AST { // gives appropriate output. st.advance(1) continue + case 'J': + // It appears that in some cases clang + // can emit a J for a template arg + // without the expected I. I don't + // know when this happens, but I've + // seen it in some large C++ programs. + if a == nil { + st.fail("unexpected template arguments") + } + var args []AST + for len(st.str) == 0 || st.str[0] != 'E' { + arg := st.templateArg() + args = append(args, arg) + } + st.advance(1) + tmpl := &Template{Name: a, Args: args} + if isCast { + st.setTemplate(a, tmpl) + st.clearTemplateArgs(args) + isCast = false + } + a = nil + next = tmpl default: st.fail("unrecognized letter in prefix") } @@ -753,19 +818,26 @@ var operators = map[string]operator{ "ad": {"&", 1}, "an": {"&", 2}, "at": {"alignof ", 1}, + "aw": {"co_await ", 1}, "az": {"alignof ", 1}, "cc": {"const_cast", 2}, "cl": {"()", 2}, + // cp is not in the ABI but is used by clang "when the call + // would use ADL except for being parenthesized." + "cp": {"()", 2}, "cm": {",", 2}, "co": {"~", 1}, "dV": {"/=", 2}, + "dX": {"[...]=", 3}, "da": {"delete[] ", 1}, "dc": {"dynamic_cast", 2}, "de": {"*", 1}, + "di": {"=", 2}, "dl": {"delete ", 1}, "ds": {".*", 2}, "dt": {".", 2}, "dv": {"/", 2}, + "dx": {"]=", 2}, "eO": {"^=", 2}, "eo": {"^", 2}, "eq": {"==", 2}, @@ -807,7 +879,10 @@ var operators = map[string]operator{ "rc": {"reinterpret_cast", 2}, "rm": {"%", 2}, "rs": {">>", 2}, + "sP": {"sizeof...", 1}, + "sZ": {"sizeof...", 1}, "sc": {"static_cast", 2}, + "ss": {"<=>", 2}, "st": {"sizeof ", 1}, "sz": {"sizeof ", 1}, "tr": {"throw", 0}, @@ -927,6 +1002,7 @@ func (st *state) javaResource() AST { // ::= TT // ::= TI // ::= TS +// ::= TA // ::= GV <(object) name> // ::= T <(base) encoding> // ::= Tc <(base) encoding> @@ -960,6 +1036,9 @@ func (st *state) specialName() AST { case 'S': t := st.demangleType(false) return &Special{Prefix: "typeinfo name for ", Val: t} + case 'A': + t := st.templateArg() + return &Special{Prefix: "template parameter object for ", Val: t} case 'h': st.callOffset('h') v := st.encoding(true, notForLocalName) @@ -1137,7 +1216,7 @@ func (st *state) demangleType(isCast bool) AST { addSubst := true q := st.cvQualifiers() - if len(q) > 0 { + if q != nil { if len(st.str) == 0 { st.fail("expected type") } @@ -1158,7 +1237,7 @@ func (st *state) demangleType(isCast bool) AST { if btype, ok := builtinTypes[st.str[0]]; ok { ret = &BuiltinType{Name: btype} st.advance(1) - if len(q) > 0 { + if q != nil { ret = &TypeWithQualifiers{Base: ret, Qualifiers: q} st.subs.add(ret) } @@ -1285,6 +1364,8 @@ func (st *state) demangleType(isCast bool) AST { case 'a': ret = &Name{Name: "auto"} + case 'c': + ret = &Name{Name: "decltype(auto)"} case 'f': ret = &BuiltinType{Name: "decimal32"} @@ -1294,6 +1375,8 @@ func (st *state) demangleType(isCast bool) AST { ret = &BuiltinType{Name: "decimal128"} case 'h': ret = &BuiltinType{Name: "half"} + case 'u': + ret = &BuiltinType{Name: "char8_t"} case 's': ret = &BuiltinType{Name: "char16_t"} case 'i': @@ -1342,7 +1425,7 @@ func (st *state) demangleType(isCast bool) AST { } } - if len(q) > 0 { + if q != nil { if _, ok := ret.(*FunctionType); ok { ret = &MethodWithQualifiers{Method: ret, Qualifiers: q, RefQualifier: ""} } else if mwq, ok := ret.(*MethodWithQualifiers); ok { @@ -1432,17 +1515,32 @@ func (st *state) demangleCastTemplateArgs(tp AST, addSubst bool) AST { } // mergeQualifiers merges two qualifer lists into one. -func mergeQualifiers(q1, q2 Qualifiers) Qualifiers { +func mergeQualifiers(q1AST, q2AST AST) AST { + if q1AST == nil { + return q2AST + } + if q2AST == nil { + return q1AST + } + q1 := q1AST.(*Qualifiers) m := make(map[string]bool) - for _, qual := range q1 { - m[qual] = true + for _, qualAST := range q1.Qualifiers { + qual := qualAST.(*Qualifier) + if len(qual.Exprs) == 0 { + m[qual.Name] = true + } } - for _, qual := range q2 { - if !m[qual] { - q1 = append(q1, qual) - m[qual] = true + rq := q1.Qualifiers + for _, qualAST := range q2AST.(*Qualifiers).Qualifiers { + qual := qualAST.(*Qualifier) + if len(qual.Exprs) > 0 { + rq = append(rq, qualAST) + } else if !m[qual.Name] { + rq = append(rq, qualAST) + m[qual.Name] = true } } + q1.Qualifiers = rq return q1 } @@ -1455,20 +1553,51 @@ var qualifiers = map[byte]string{ } // ::= [r] [V] [K] -func (st *state) cvQualifiers() Qualifiers { - var q Qualifiers +func (st *state) cvQualifiers() AST { + var q []AST +qualLoop: for len(st.str) > 0 { if qv, ok := qualifiers[st.str[0]]; ok { - q = append([]string{qv}, q...) + qual := &Qualifier{Name: qv} + q = append([]AST{qual}, q...) st.advance(1) - } else if len(st.str) > 1 && st.str[:2] == "Dx" { - q = append([]string{"transaction_safe"}, q...) - st.advance(2) + } else if len(st.str) > 1 && st.str[0] == 'D' { + var qual AST + switch st.str[1] { + case 'x': + qual = &Qualifier{Name: "transaction_safe"} + st.advance(2) + case 'o': + qual = &Qualifier{Name: "noexcept"} + st.advance(2) + case 'O': + st.advance(2) + expr := st.expression() + if len(st.str) == 0 || st.str[0] != 'E' { + st.fail("expected E after computed noexcept expression") + } + st.advance(1) + qual = &Qualifier{Name: "noexcept", Exprs: []AST{expr}} + case 'w': + st.advance(2) + parmlist := st.parmlist() + if len(st.str) == 0 || st.str[0] != 'E' { + st.fail("expected E after throw parameter list") + } + st.advance(1) + qual = &Qualifier{Name: "throw", Exprs: parmlist} + default: + break qualLoop + } + q = append([]AST{qual}, q...) } else { break } } - return q + if len(q) == 0 { + return nil + } + return &Qualifiers{Qualifiers: q} } // ::= R @@ -1676,7 +1805,7 @@ func (st *state) compactNumber() int { // whatever the template parameter would be expanded to here. We sort // this out in substitution and simplify. func (st *state) templateParam() AST { - if len(st.templates) == 0 { + if len(st.templates) == 0 && st.inLambda == 0 { st.fail("template parameter not in scope of template") } off := st.off @@ -1684,6 +1813,13 @@ func (st *state) templateParam() AST { st.checkChar('T') n := st.compactNumber() + if st.inLambda > 0 { + // g++ mangles lambda auto params as template params. + // Apparently we can't encounter a template within a lambda. + // See https://gcc.gnu.org/PR78252. + return &LambdaAuto{Index: n} + } + template := st.templates[len(st.templates)-1] if template == nil { @@ -1722,6 +1858,10 @@ func (st *state) setTemplate(a AST, tmpl *Template) { } a.Template = tmpl return false + case *Closure: + // There are no template params in closure types. + // https://gcc.gnu.org/PR78252. + return false default: for _, v := range seen { if v == a { @@ -1811,12 +1951,60 @@ func (st *state) exprList(stop byte) AST { // ::= <(unary) operator-name> // ::= <(binary) operator-name> // ::= <(trinary) operator-name> +// ::= pp_ +// ::= mm_ +// ::= cl + E // ::= cl + E +// ::= cv +// ::= cv _ * E +// ::= tl * E +// ::= il * E +// ::= [gs] nw * _ E +// ::= [gs] nw * _ +// ::= [gs] na * _ E +// ::= [gs] na * _ +// ::= [gs] dl +// ::= [gs] da +// ::= dc +// ::= sc +// ::= cc +// ::= rc +// ::= ti +// ::= te // ::= st +// ::= sz +// ::= at +// ::= az +// ::= nx // ::= -// ::= sr -// ::= sr +// ::= +// ::= dt +// ::= pt +// ::= ds +// ::= sZ +// ::= sZ +// ::= sP * E +// ::= sp +// ::= fl +// ::= fr +// ::= fL +// ::= fR +// ::= tw +// ::= tr +// ::= // ::= +// +// ::= fp _ +// ::= fp +// ::= fL p _ +// ::= fL p +// ::= fpT +// +// ::= +// ::= di +// ::= dx +// ::= dX +// func (st *state) expression() AST { if len(st.str) == 0 { st.fail("expected expression") @@ -1826,61 +2014,7 @@ func (st *state) expression() AST { } else if st.str[0] == 'T' { return st.templateParam() } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'r' { - st.advance(2) - if len(st.str) == 0 { - st.fail("expected unresolved type") - } - switch st.str[0] { - case 'T', 'D', 'S': - t := st.demangleType(false) - n := st.baseUnresolvedName() - n = &Qualified{Scope: t, Name: n, LocalName: false} - if len(st.str) > 0 && st.str[0] == 'I' { - args := st.templateArgs() - n = &Template{Name: n, Args: args} - } - return n - default: - var s AST - if st.str[0] == 'N' { - st.advance(1) - s = st.demangleType(false) - } - for len(st.str) == 0 || st.str[0] != 'E' { - // GCC does not seem to follow the ABI here. - // It can emit type/name without an 'E'. - if s != nil && len(st.str) > 0 && !isDigit(st.str[0]) { - if q, ok := s.(*Qualified); ok { - a := q.Scope - if t, ok := a.(*Template); ok { - st.subs.add(t.Name) - st.subs.add(t) - } else { - st.subs.add(a) - } - return s - } - } - n := st.sourceName() - if len(st.str) > 0 && st.str[0] == 'I' { - st.subs.add(n) - args := st.templateArgs() - n = &Template{Name: n, Args: args} - } - if s == nil { - s = n - } else { - s = &Qualified{Scope: s, Name: n, LocalName: false} - } - st.subs.add(s) - } - if s == nil { - st.fail("missing scope in unresolved name") - } - st.advance(1) - n := st.baseUnresolvedName() - return &Qualified{Scope: s, Name: n, LocalName: false} - } + return st.unresolvedName() } else if st.str[0] == 's' && len(st.str) > 1 && st.str[1] == 'p' { st.advance(2) e := st.expression() @@ -1910,9 +2044,25 @@ func (st *state) expression() AST { st.advance(1) return &FunctionParam{Index: 0} } else { + // We can see qualifiers here, but we don't + // include them in the demangled string. + st.cvQualifiers() index := st.compactNumber() return &FunctionParam{Index: index + 1} } + } else if st.str[0] == 'f' && len(st.str) > 2 && st.str[1] == 'L' && isDigit(st.str[2]) { + st.advance(2) + // We don't include the scope count in the demangled string. + st.number() + if len(st.str) == 0 || st.str[0] != 'p' { + st.fail("expected p after function parameter scope count") + } + st.advance(1) + // We can see qualifiers here, but we don't include them + // in the demangled string. + st.cvQualifiers() + index := st.compactNumber() + return &FunctionParam{Index: index + 1} } else if isDigit(st.str[0]) || (st.str[0] == 'o' && len(st.str) > 1 && st.str[1] == 'n') { if st.str[0] == 'o' { // Skip operator function ID. @@ -1974,13 +2124,15 @@ func (st *state) expression() AST { left, _ = st.operatorName(true) right = st.expression() return &Fold{Left: code[1] == 'l', Op: left, Arg1: right, Arg2: nil} + } else if code == "di" { + left, _ = st.unqualifiedName() } else { left = st.expression() } - if code == "cl" { + if code == "cl" || code == "cp" { right = st.exprList('E') } else if code == "dt" || code == "pt" { - right, _ = st.unqualifiedName() + right = st.unresolvedName() if len(st.str) > 0 && st.str[0] == 'I' { args := st.templateArgs() right = &Template{Name: right, Args: args} @@ -2033,6 +2185,82 @@ func (st *state) expression() AST { } } +// ::= [gs] +// ::= sr +// ::= srN + E +// ::= [gs] sr + E +func (st *state) unresolvedName() AST { + if len(st.str) >= 2 && st.str[:2] == "gs" { + st.advance(2) + n := st.unresolvedName() + return &Unary{ + Op: &Operator{Name: "::"}, + Expr: n, + Suffix: false, + SizeofType: false, + } + } else if len(st.str) >= 2 && st.str[:2] == "sr" { + st.advance(2) + if len(st.str) == 0 { + st.fail("expected unresolved type") + } + switch st.str[0] { + case 'T', 'D', 'S': + t := st.demangleType(false) + n := st.baseUnresolvedName() + n = &Qualified{Scope: t, Name: n, LocalName: false} + if len(st.str) > 0 && st.str[0] == 'I' { + args := st.templateArgs() + n = &Template{Name: n, Args: args} + st.subs.add(n) + } + return n + default: + var s AST + if st.str[0] == 'N' { + st.advance(1) + s = st.demangleType(false) + } + for len(st.str) == 0 || st.str[0] != 'E' { + // GCC does not seem to follow the ABI here. + // It can emit type/name without an 'E'. + if s != nil && len(st.str) > 0 && !isDigit(st.str[0]) { + if q, ok := s.(*Qualified); ok { + a := q.Scope + if t, ok := a.(*Template); ok { + st.subs.add(t.Name) + st.subs.add(t) + } else { + st.subs.add(a) + } + return s + } + } + n := st.sourceName() + if len(st.str) > 0 && st.str[0] == 'I' { + st.subs.add(n) + args := st.templateArgs() + n = &Template{Name: n, Args: args} + } + if s == nil { + s = n + } else { + s = &Qualified{Scope: s, Name: n, LocalName: false} + } + st.subs.add(s) + } + if s == nil { + st.fail("missing scope in unresolved name") + } + st.advance(1) + n := st.baseUnresolvedName() + return &Qualified{Scope: s, Name: n, LocalName: false} + } + } else { + return st.baseUnresolvedName() + } +} + // ::= // ::= on // ::= on @@ -2098,7 +2326,14 @@ func (st *state) exprPrimary() AST { st.advance(1) } if len(st.str) > 0 && st.str[0] == 'E' { - st.fail("missing literal value") + if bt, ok := t.(*BuiltinType); ok && bt.Name == "decltype(nullptr)" { + // A nullptr should not have a value. + // We accept one if present because GCC + // used to generate one. + // https://gcc.gnu.org/PR91979. + } else { + st.fail("missing literal value") + } } i := 0 for len(st.str) > i && st.str[i] != 'E' { @@ -2115,17 +2350,29 @@ func (st *state) exprPrimary() AST { return ret } -// ::= _ <(non-negative) number> +// ::= _ <(non-negative) number> (when number < 10) +// __ <(non-negative) number> _ (when number >= 10) func (st *state) discriminator(a AST) AST { if len(st.str) == 0 || st.str[0] != '_' { return a } off := st.off st.advance(1) + trailingUnderscore := false + if len(st.str) > 0 && st.str[0] == '_' { + st.advance(1) + trailingUnderscore = true + } d := st.number() if d < 0 { st.failEarlier("invalid negative discriminator", st.off-off) } + if trailingUnderscore && d >= 10 { + if len(st.str) == 0 || st.str[0] != '_' { + st.fail("expected _ after discriminator >= 10") + } + st.advance(1) + } // We don't currently print out the discriminator, so we don't // save it. return a @@ -2135,15 +2382,15 @@ func (st *state) discriminator(a AST) AST { func (st *state) closureTypeName() AST { st.checkChar('U') st.checkChar('l') + st.inLambda++ types := st.parmlist() + st.inLambda-- if len(st.str) == 0 || st.str[0] != 'E' { st.fail("expected E after closure type name") } st.advance(1) num := st.compactNumber() - ret := &Closure{Types: types, Num: num} - st.subs.add(ret) - return ret + return &Closure{Types: types, Num: num} } // ::= Ut [ ] _ @@ -2294,31 +2541,92 @@ func (st *state) substitution(forPrefix bool) AST { // We need to update any references to template // parameters to refer to the currently active // template. + + // When copying a Typed we may need to adjust + // the templates. + copyTemplates := st.templates + var oldInLambda []int + + // pushTemplate is called from skip, popTemplate from copy. + pushTemplate := func(template *Template) { + copyTemplates = append(copyTemplates, template) + oldInLambda = append(oldInLambda, st.inLambda) + st.inLambda = 0 + } + popTemplate := func() { + copyTemplates = copyTemplates[:len(copyTemplates)-1] + st.inLambda = oldInLambda[len(oldInLambda)-1] + oldInLambda = oldInLambda[:len(oldInLambda)-1] + } + copy := func(a AST) AST { - tp, ok := a.(*TemplateParam) - if !ok { + var index int + switch a := a.(type) { + case *Typed: + // Remove the template added in skip. + if _, ok := a.Name.(*Template); ok { + popTemplate() + } + return nil + case *Closure: + // Undo the decrement in skip. + st.inLambda-- return nil + case *TemplateParam: + index = a.Index + case *LambdaAuto: + // A lambda auto parameter is represented + // as a template parameter, so we may have + // to change back when substituting. + index = a.Index + default: + return nil + } + if st.inLambda > 0 { + if _, ok := a.(*LambdaAuto); ok { + return nil + } + return &LambdaAuto{Index: index} } - if len(st.templates) == 0 { + var template *Template + if len(copyTemplates) > 0 { + template = copyTemplates[len(copyTemplates)-1] + } else if rt, ok := ret.(*Template); ok { + // At least with clang we can see a template + // to start, and sometimes we need to refer + // to it. There is probably something wrong + // here. + template = rt + } else { st.failEarlier("substituted template parameter not in scope of template", dec) } - template := st.templates[len(st.templates)-1] if template == nil { // This template parameter is within // the scope of a cast operator. - return &TemplateParam{Index: tp.Index, Template: nil} + return &TemplateParam{Index: index, Template: nil} } - if tp.Index >= len(template.Args) { - st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", tp.Index, len(template.Args)), dec) + if index >= len(template.Args) { + st.failEarlier(fmt.Sprintf("substituted template index out of range (%d >= %d)", index, len(template.Args)), dec) } - return &TemplateParam{Index: tp.Index, Template: template} + return &TemplateParam{Index: index, Template: template} } var seen []AST skip := func(a AST) bool { - if _, ok := a.(*Typed); ok { - return true + switch a := a.(type) { + case *Typed: + if template, ok := a.Name.(*Template); ok { + // This template is removed in copy. + pushTemplate(template) + } + return false + case *Closure: + // This is decremented in copy. + st.inLambda++ + return false + case *TemplateParam, *LambdaAuto: + return false } for _, v := range seen { if v == a { @@ -2328,6 +2636,7 @@ func (st *state) substitution(forPrefix bool) AST { seen = append(seen, a) return false } + if c := ret.Copy(copy, skip); c != nil { return c } @@ -2350,6 +2659,7 @@ func (st *state) substitution(forPrefix bool) AST { if len(st.str) > 0 && st.str[0] == 'B' { a = st.taggedName(a) + st.subs.add(a) } return a -- cgit mrf-deployment