Skip to content

[pull] swiftwasm from master #673

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 68 commits into from
Apr 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
7e82b6f
[benchmark] Add HTTP2StateMachine benchmark
Lukasa Oct 19, 2018
991878c
clean up some stdlib unittest warnings
brettkoonce Nov 22, 2019
396ba4f
Move out enum tests into a separate CXXInterop/enum directory
scentini Mar 2, 2020
03e4f5f
[benchmark] Package.swift: Don’t trap on stray files under single-sou…
lorentey Mar 24, 2020
d2bd596
Fixed incorrect comment in SwiftReflectionTest
daeken Mar 28, 2020
fd1dcf7
[NFC] Correct code blocks in property wrapper doc comments
hborla Apr 3, 2020
d22b984
[Expr] Allow OpaqueValueExpr to store an underlying expression
hborla Apr 3, 2020
c301176
[ConstraintSystem] Allow SolutionApplicationTarget to store the
hborla Apr 3, 2020
e82a0b9
Runtime: Implement wrapper function for metadata access functions
Azoy Feb 23, 2020
bbfcb55
[Property Wrappers] Inject the opaque value placeholder for a property
hborla Apr 3, 2020
c130848
[Test] Add a regression test for property wrapper backing initializer…
hborla Apr 4, 2020
5f00a1b
[SILGen] In a memberwise initializer, apply the property wrapper backing
hborla Apr 6, 2020
f35efee
Move metadataAccessorCall to SwiftShims
Azoy Apr 6, 2020
65105f3
[Property Wrappers] Introduce a new Expr node for the property wrapper
hborla Apr 9, 2020
4764564
[SILGen] Remove an unnecessary scope in emitImplicitValueConstructor
hborla Apr 9, 2020
b16e003
[debugging-the-compiler] Add to bisecting optimization passes a short…
gottesmm Apr 10, 2020
815ecad
[Property Wrappers] Don't continue on to synthesizing and type checki…
hborla Apr 10, 2020
1d7ce7e
[build-script] Add sanitizer support to indexstore-db product
benlangmuir Apr 10, 2020
72dbdb0
[SymbolGraph] Look at inherited protocols for default implementations
bitjammer Apr 13, 2020
65fe324
Fix macOS indexstore-db preset
benlangmuir Apr 13, 2020
59fe523
Merge remote-tracking branch 'origin/master' into fortify-benchmarks
lorentey Apr 14, 2020
c1bf5c9
[benchmark] Fix thinko
lorentey Apr 14, 2020
fa6bede
build: explicitly pass the path to python2,python3
compnerd Apr 14, 2020
f1b4101
MergeFunctions: use new LLVM API to create a call.
eeckstein Apr 14, 2020
80f0e39
[line-directive] Escape literal '['
davezarzycki Apr 14, 2020
6837225
Merge pull request #31009 from eeckstein/merge-funcs
swift-ci Apr 14, 2020
17b52ca
test: Add parens to print for Python3 compatibility
RLovelett Apr 12, 2020
6f01826
Merge pull request #31010 from davezarzycki/pr31010
swift-ci Apr 14, 2020
36667b9
Merge pull request #31006 from compnerd/explicit-paths
compnerd Apr 14, 2020
f9610de
Merge pull request #31000 from bitjammer/acgarland/rdar-61178480-indi…
bitjammer Apr 14, 2020
43bb415
Merge pull request #30963 from benlangmuir/isdb-san
benlangmuir Apr 14, 2020
9ae46a3
Disable creating swift-api-digester dSYM to reduce toolchain size
shahmishal Apr 14, 2020
9b1c4c6
Merge pull request #30942 from gottesmm/debug_compiler_autobisect
gottesmm Apr 14, 2020
f943a88
[SourceKit] Don't use clang build sessions when validation is disabled
rintaro Apr 14, 2020
66e8572
Merge pull request #30807 from hborla/property-wrapper-refactoring
hborla Apr 14, 2020
0f5bdb4
Add a comment for removing debug symbols for swift-api-digester from …
shahmishal Apr 14, 2020
06baf82
[docs] Change two command lines to be an inline literal instead of no…
gottesmm Apr 14, 2020
a3657e1
[doc] Describe how to use git-bisect in the presence of branch forwar…
gottesmm Apr 14, 2020
dbbd6c9
runtime: extend shims to x86
compnerd Apr 14, 2020
1036302
[Diagnostics] Add a `getLoc` method to `FailureDiagnostic`
xedin Apr 10, 2020
5dbced9
[Diagnostics] Allow failure diagnostic implementation to extend `getA…
xedin Apr 10, 2020
cdee9a1
[Diagnostics] Use new `getLoc` and `getSourceRange` methods
xedin Apr 11, 2020
1dc6a0a
[Diagnostics] Allow invalid initializer ref diagnostics point to `.init`
xedin Apr 14, 2020
45d54b6
build: add a workaround for the build to use Python2 instead of Python3
compnerd Apr 14, 2020
ad48b93
Merge pull request #31011 from RLovelett/python3-fix-print
compnerd Apr 14, 2020
7dd5b47
Merge pull request #31017 from gottesmm/pr-891666424206195516c645418a…
swift-ci Apr 14, 2020
3198436
[AutoDiff] Add `REQUIRES: CPU=x86_64` to IRGen test.
dan-zheng Apr 14, 2020
b748920
[Diagnostic] Non-ephemeral pointer init diagnostic should point to `.…
xedin Apr 14, 2020
bff1786
[docs] Add a section on running @swift-ci based non-executable device…
gottesmm Apr 14, 2020
bb2a701
Merge pull request #31021 from gottesmm/pr-c115ac2d5c3c0400c2b76de571…
shahmishal Apr 14, 2020
bd7eb1c
Merge pull request #31013 from rintaro/sourcekit-buildsession-implici…
rintaro Apr 14, 2020
8c42386
Merge pull request #31018 from gottesmm/pr-d6426d88ab60dd2b653c227ec2…
shahmishal Apr 14, 2020
ce324d3
[Diagnostics] Missing member diagnostic associated with module should…
xedin Apr 14, 2020
b63aeb0
Merge pull request #31020 from compnerd/python-fallback
shahmishal Apr 14, 2020
ee95b8b
Merge pull request #30601 from lorentey/fortify-benchmarks
lorentey Apr 14, 2020
419c221
Removes redundant buffer zeroing in Metal.swift by using `init(unsafe…
valeriyvan Apr 14, 2020
0eb9180
Merge pull request #31022 from apple/autodiff-testing
shahmishal Apr 14, 2020
4fd19a8
Merge pull request #31019 from compnerd/x86-shims
compnerd Apr 14, 2020
8a1a194
[SR-12460] Don't crash when missing a type in a Diagnostic message. (…
blueeor Apr 14, 2020
c0776be
Merge pull request #28435 from brettkoonce/stdlib-unittest-cleanup
CodaFi Apr 15, 2020
0501232
Merge pull request #31012 from apple/shahmishal/drop-swift-api-digest…
shahmishal Apr 15, 2020
010520a
Merge pull request #30967 from xedin/add-loc-to-failure-diagnostic
xedin Apr 15, 2020
dba0424
[Preset] Generate line number debug information only to reduce the sy…
shahmishal Apr 15, 2020
3aee49d
Merge pull request #30703 from daeken/patch-1
CodaFi Apr 15, 2020
5fd6e98
Merge pull request #30024 from Azoy/calling-metadata-accessor-from-sw…
CodaFi Apr 15, 2020
80cc726
Merge pull request #19954 from Lukasa/cb-bench-h2-enumeration
CodaFi Apr 15, 2020
c9e8588
Merge pull request #30182 from scentini/enum-cxx
swift-ci Apr 15, 2020
061c6d0
Merge pull request #31029 from apple/shahmishal/line-debug-info-only
shahmishal Apr 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,13 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
endif()

find_package(Python2 COMPONENTS Interpreter REQUIRED)
find_package(Python3 COMPONENTS Interpreter REQUIRED)
find_package(Python3 COMPONENTS Interpreter)
if(NOT Python3_Interpreter_FOUND)
message(WARNING "Python3 not found, using python2 as a fallback")
add_executable(Python3::Interpreter IMPORTED)
set_target_properties(Python3::Interpreter PROPERTIES
IMPORTED_LOCATION ${Python2_EXECUTABLE})
endif()

#
# Find optional dependencies.
Expand Down
3 changes: 1 addition & 2 deletions benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ set(SWIFT_BENCH_MODULES
single-source/Hanoi
single-source/Hash
single-source/Histogram
single-source/InsertCharacter
single-source/IntegerParsing
single-source/HTTP2StateMachine
single-source/Integrate
single-source/IterateData
single-source/Join
Expand Down
16 changes: 8 additions & 8 deletions benchmark/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ func getSingleSourceLibraries(subDirectory: String) -> [String] {
let fileURLs = try! f.contentsOfDirectory(at: dirURL,
includingPropertiesForKeys: nil)
return fileURLs.compactMap { (path: URL) -> String? in
let c = path.lastPathComponent.split(separator: ".")
// Too many components. Must be a gyb file.
if c.count > 2 {
return nil
}
if c[1] != "swift" {
guard let lastDot = path.lastPathComponent.lastIndex(of: ".") else {
return nil
}
let ext = String(path.lastPathComponent.suffix(from: lastDot))
guard ext == ".swift" else { return nil }

let name = String(path.lastPathComponent.prefix(upTo: lastDot))

let name = String(c[0])
// Test names must have a single component.
if name.contains(".") { return nil }

// We do not support this test.
if unsupportedTests.contains(name) {
// We do not support this test.
return nil
}

Expand Down
390 changes: 390 additions & 0 deletions benchmark/single-source/HTTP2StateMachine.swift

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions benchmark/utils/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ import FloatingPointPrinting
import Hanoi
import Hash
import Histogram
import InsertCharacter
import IntegerParsing
import HTTP2StateMachine
import Integrate
import IterateData
import Join
Expand Down Expand Up @@ -268,8 +267,7 @@ registerBenchmark(FloatingPointPrinting)
registerBenchmark(Hanoi)
registerBenchmark(HashTest)
registerBenchmark(Histogram)
registerBenchmark(InsertCharacter)
registerBenchmark(IntegerParsing)
registerBenchmark(HTTP2StateMachine)
registerBenchmark(IntegrateTest)
registerBenchmark(IterateData)
registerBenchmark(Join)
Expand Down
11 changes: 11 additions & 0 deletions docs/ContinuousIntegration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [Source Compatibility Testing](#source-compatibility-testing)
- [Sourcekit Stress Testing](#sourcekit-stress-testing)
- [Specific Preset Testing](#specific-preset-testing)
- [Running Non-Executable Device Tests](#running-non-executable-device-tests)
- [Build Swift Toolchain](#build-swift-toolchain)
- [Testing Compiler Performance](#testing-compiler-performance)
- [Swift Community Hosted CI Pull Request Testing](#swift-community-hosted-ci-pull-request-testing)
Expand Down Expand Up @@ -161,8 +162,18 @@ For example:
```
preset=buildbot_incremental,tools=RA,stdlib=RD,smoketest=macosx,single-thread
@swift-ci Please test with preset macOS
```

### Running Non-Executable Device Tests

Using the specific preset testing, one can run non-executable device tests by
telling swift-ci:

```
preset=buildbot,tools=RA,stdlib=RD,test=non_executable
@swift-ci Please test with preset macOS
```

### Build Swift Toolchain

Platform | Comment | Check Status
Expand Down
81 changes: 75 additions & 6 deletions docs/DebuggingTheCompiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ where to stop in the debugger. Rather than trying to guess/check if one has an
asserts swift compiler, one can use the following options to cause the
diagnostic engine to assert on the first error/warning:

* -Xllvm -swift-diagnostics-assert-on-error=1
* -Xllvm -swift-diagnostics-assert-on-warning=1
* ``-Xllvm -swift-diagnostics-assert-on-error=1``
* ``-Xllvm -swift-diagnostics-assert-on-warning=1``

These allow one to dump a stack trace of where the diagnostic is being emitted
(if run without a debugger) or drop into the debugger if a debugger is attached.
Expand Down Expand Up @@ -548,10 +548,17 @@ it's quite easy to do this manually:

a. Add the compiler option ``-Xllvm -sil-opt-pass-count=<n>``, where ``<n>``
is the number of optimizations to run.
b. Bisect: find n where the executable crashes, but does not crash with n-1.
Note that n can be quite large, e.g. > 100000 (just try
n = 10, 100, 1000, 10000, etc. to find an upper bound).
c. Add another option ``-Xllvm -sil-print-pass-name``. The output can be

b. Bisect: find n where the executable crashes, but does not crash
with n-1. First just try n = 10, 100, 1000, 10000, etc. to find
an upper bound). Then can either bisect the invocation by hand or
place the invocation into a script and use
``./llvm-project/llvm/utils/bisect`` to automatically bisect
based on the scripts error code. Example invocation::

bisect --start=0 --end=10000 ./invoke_swift_passing_N.sh "%(count)s"

c. Once one finds ``n``, Add another option ``-Xllvm -sil-print-pass-name``. The output can be
large, so it's best to redirect stderr to a file (``2> output``).
In the output search for the last pass before ``stage Address Lowering``.
It should be the ``Run #<n-1>``. This line tells you the name of the bad
Expand Down Expand Up @@ -687,3 +694,65 @@ Multiple Logs at a Time
Note, you can also turn on more than one log at a time as well, e.x.::

(lldb) log enable -f /tmp/lldb-types-log.txt lldb types expression

Using git-bisect in the presence of branch forwarding/feature branches
======================================================================

``git-bisect`` is a useful tool for finding where a regression was
introduced. Sadly ``git-bisect`` does not handle long lived branches
and will in fact choose commits from upstream branches that may be
missing important content from the downstream branch. As an example,
consider a situation where one has the following straw man commit flow
graph::

github/master -> github/tensorflow

In this case if one attempts to use ``git-bisect`` on
github/tensorflow, ``git-bisect`` will sometimes choose commits from
github/master resulting in one being unable to compile/test specific
tensorflow code that has not been upstreamed yet. Even worse, what if
we are trying to bisect in between two that were branched from
github/tensorflow and have had subsequent commits cherry-picked on
top. Without any loss of generality, lets call those two tags
``tag-tensorflow-bad`` and ``tag-tensorflow-good``. Since both of
these tags have had commits cherry-picked on top, they are technically
not even on the github/tensorflow branch, but rather in a certain
sense are a tag of a feature branch from master/tensorflow. So,
``git-bisect`` doesn't even have a clear history to bisect on in
multiple ways.

With those constraints in mind, we can bisect! We just need to be
careful how we do it. Lets assume that we have a test script called
``test.sh`` that indicates error by the error code. With that in hand,
we need to compute the least common ancestor of the good/bad
commits. This is traditionally called the "merge base" of the
commits. We can compute this as so::

TAG_MERGE_BASE=$(git merge-base tags/tag-tensorflow-bad tags/tag-tensorflow-good)

Given that both tags were taken from the feature branch, the reader
can prove to themselves that this commit is guaranteed to be on
``github/tensorflow`` and not ``github/master`` since all commits from
``github/master`` are forwarded using git merges.

Then lets assume that we checked out ``$TAG_MERGE_BASE`` and then ran
``test.sh`` and did not hit any error. Ok, we can not bisect. Sadly,
as mentioned above if we run git-bisect in between ``$TAG_MERGE_BASE``
and ``tags/tag-tensorflow-bad``, ``git-bisect`` will sometimes choose
commits from ``github/master`` which would cause ``test.sh`` to fail
if we are testing tensorflow specific code! To work around this
problem, we need to start our bisect and then tell ``git-bisect`` to
ignore those commits by using the skip sub command::

git bisect start tags/tag-tensorflow-bad $TAG_MERGE_BASE
for rev in $(git rev-list $TAG_MERGE_BASE..tags/tag-tensorflow-bad --merges --first-parent); do
git rev-list $rev^2 --not $rev^
done | xargs git bisect skip

Once this has been done, one uses ``git-bisect`` normally. One thing
to be aware of is that ``git-bisect`` will return a good/bad commits
on the feature branch and if one of those commits is a merge from the
upstream branch, one will need to analyze the range of commits from
upstream for the bad commit afterwards. The commit range in the merge
should be relatively small though compared with the large git history
one just bisected.
2 changes: 1 addition & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5243,7 +5243,7 @@ class VarDecl : public AbstractStorageDecl {
///
/// \code
/// @Lazy var i = 17
/// \end
/// \endcode
///
/// Or when there is no initializer but each composed property wrapper has
/// a suitable `init(wrappedValue:)`.
Expand Down
4 changes: 2 additions & 2 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -902,8 +902,8 @@ ERROR(nonstatic_operator_in_nominal,none,
"operator %0 declared in type %1 must be 'static'",
(Identifier, DeclName))
ERROR(nonstatic_operator_in_extension,none,
"operator %0 declared in extension of %1 must be 'static'",
(Identifier, TypeRepr*))
"operator %0 declared in extension%select{| of %2}1 must be 'static'",
(Identifier, bool, TypeRepr*))
ERROR(nonfinal_operator_in_class,none,
"operator %0 declared in non-final class %1 must be 'final'",
(Identifier, Type))
Expand Down
56 changes: 55 additions & 1 deletion include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4041,7 +4041,61 @@ class OpaqueValueExpr : public Expr {
SourceRange getSourceRange() const { return Range; }

static bool classof(const Expr *E) {
return E->getKind() == ExprKind::OpaqueValue;
return E->getKind() == ExprKind::OpaqueValue;
}
};

/// A placeholder to substitute with a \c wrappedValue initialization expression
/// for a property with an attached property wrapper.
///
/// Wrapped value placeholder expressions are injected around the
/// \c wrappedValue argument in a synthesized \c init(wrappedValue:)
/// call. This injection happens for properties with attached property wrappers
/// that can be initialized out-of-line with a wrapped value expression, rather
/// than calling \c init(wrappedValue:) explicitly.
///
/// Wrapped value placeholders store the original initialization expression
/// if one exists, along with an opaque value placeholder that can be bound
/// to a different wrapped value expression.
class PropertyWrapperValuePlaceholderExpr : public Expr {
SourceRange Range;
OpaqueValueExpr *Placeholder;
Expr *WrappedValue;

PropertyWrapperValuePlaceholderExpr(SourceRange Range, Type Ty,
OpaqueValueExpr *placeholder,
Expr *wrappedValue)
: Expr(ExprKind::PropertyWrapperValuePlaceholder, /*Implicit=*/true, Ty),
Range(Range), Placeholder(placeholder), WrappedValue(wrappedValue) {}

public:
static PropertyWrapperValuePlaceholderExpr *
create(ASTContext &ctx, SourceRange range, Type ty, Expr *wrappedValue);

/// The original wrappedValue initialization expression provided via
/// \c = on a proprety with attached property wrappers.
Expr *getOriginalWrappedValue() const {
return WrappedValue;
}

void setOriginalWrappedValue(Expr *value) {
WrappedValue = value;
}

/// An opaque value placeholder that will be used to substitute in a
/// different wrapped value expression for out-of-line initialization.
OpaqueValueExpr *getOpaqueValuePlaceholder() const {
return Placeholder;
}

void setOpaqueValuePlaceholder(OpaqueValueExpr *placeholder) {
Placeholder = placeholder;
}

SourceRange getSourceRange() const { return Range; }

static bool classof(const Expr *E) {
return E->getKind() == ExprKind::PropertyWrapperValuePlaceholder;
}
};

Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ExprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ EXPR(VarargExpansion, Expr)
EXPR(DynamicType, Expr)
EXPR(RebindSelfInConstructor, Expr)
EXPR(OpaqueValue, Expr)
EXPR(PropertyWrapperValuePlaceholder, Expr)
EXPR(DefaultArgument, Expr)
EXPR(BindOptional, Expr)
EXPR(OptionalEvaluation, Expr)
Expand Down
13 changes: 7 additions & 6 deletions include/swift/AST/PropertyWrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ struct PropertyWrapperBackingPropertyInfo {
///
/// \code
/// @Lazy var i = 17
/// \end
/// \endcode
///
/// This is the specified initial value (\c 17), which is suitable for
/// embedding in the expression \c initializeFromOriginal.
Expand Down Expand Up @@ -190,12 +190,13 @@ void simple_display(
llvm::raw_ostream &out,
const PropertyWrapperBackingPropertyInfo &backingInfo);

/// Given the initializer for the given property with an attached property
/// wrapper, dig out the original initialization expression.
/// Given the initializer for a property with an attached property wrapper,
/// dig out the wrapped value placeholder for the original initialization
/// expression.
///
/// Cannot just dig out the getOriginalInit() value because this function checks
/// types, etc. Erroneous code won't return a result from here.
Expr *findOriginalPropertyWrapperInitialValue(VarDecl *var, Expr *init);
/// \note The wrapped value placeholder is injected for properties that can
/// be initialized out-of-line using an expression of the wrapped property type.
PropertyWrapperValuePlaceholderExpr *findWrappedValuePlaceholder(Expr *init);

} // end namespace swift

Expand Down
12 changes: 12 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2511,6 +2511,18 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

void visitPropertyWrapperValuePlaceholderExpr(
PropertyWrapperValuePlaceholderExpr *E) {
printCommon(E, "property_wrapper_value_placeholder_expr");
OS << '\n';
printRec(E->getOpaqueValuePlaceholder());
if (auto *value = E->getOriginalWrappedValue()) {
OS << '\n';
printRec(value);
}
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

void visitDefaultArgumentExpr(DefaultArgumentExpr *E) {
printCommon(E, "default_argument_expr");
OS << " default_args_owner=";
Expand Down
17 changes: 17 additions & 0 deletions lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,23 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,

Expr *visitOpaqueValueExpr(OpaqueValueExpr *E) { return E; }

Expr *visitPropertyWrapperValuePlaceholderExpr(
PropertyWrapperValuePlaceholderExpr *E) {
if (auto *placeholder = doIt(E->getOpaqueValuePlaceholder()))
E->setOpaqueValuePlaceholder(dyn_cast<OpaqueValueExpr>(placeholder));
else
return nullptr;

if (E->getOriginalWrappedValue()) {
if (auto *newValue = doIt(E->getOriginalWrappedValue()))
E->setOriginalWrappedValue(newValue);
else
return nullptr;
}

return E;
}

Expr *visitDefaultArgumentExpr(DefaultArgumentExpr *E) { return E; }

Expr *visitInterpolatedStringLiteralExpr(InterpolatedStringLiteralExpr *E) {
Expand Down
Loading