194 changes: 106 additions & 88 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4832,8 +4832,10 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
LocalInstantiationScope Local(*this);
Result = SubstInitializer(UninstExpr, MutiLevelArgList,
/*DirectInit*/false);
runWithSufficientStackSpace(CallLoc, [&] {
Result = SubstInitializer(UninstExpr, MutiLevelArgList,
/*DirectInit*/false);
});
}
if (Result.isInvalid())
return true;
Expand Down Expand Up @@ -15175,6 +15177,17 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (IsRecursiveCall && OdrUse == OdrUseContext::Used)
OdrUse = OdrUseContext::FormallyOdrUsed;

// Trivial default constructors and destructors are never actually used.
// FIXME: What about other special members?
if (Func->isTrivial() && !Func->hasAttr<DLLExportAttr>() &&
OdrUse == OdrUseContext::Used) {
if (auto *Constructor = dyn_cast<CXXConstructorDecl>(Func))
if (Constructor->isDefaultConstructor())
OdrUse = OdrUseContext::FormallyOdrUsed;
if (isa<CXXDestructorDecl>(Func))
OdrUse = OdrUseContext::FormallyOdrUsed;
}

// C++20 [expr.const]p12:
// A function [...] is needed for constant evaluation if it is [...] a
// constexpr function that is named by an expression that is potentially
Expand Down Expand Up @@ -15235,98 +15248,101 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,

// If we need a definition, try to create one.
if (NeedDefinition && !Func->getBody()) {
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
if (Constructor->isDefaultConstructor()) {
if (Constructor->isTrivial() &&
!Constructor->hasAttr<DLLExportAttr>())
runWithSufficientStackSpace(Loc, [&] {
if (CXXConstructorDecl *Constructor =
dyn_cast<CXXConstructorDecl>(Func)) {
Constructor = cast<CXXConstructorDecl>(Constructor->getFirstDecl());
if (Constructor->isDefaulted() && !Constructor->isDeleted()) {
if (Constructor->isDefaultConstructor()) {
if (Constructor->isTrivial() &&
!Constructor->hasAttr<DLLExportAttr>())
return;
DefineImplicitDefaultConstructor(Loc, Constructor);
} else if (Constructor->isCopyConstructor()) {
DefineImplicitCopyConstructor(Loc, Constructor);
} else if (Constructor->isMoveConstructor()) {
DefineImplicitMoveConstructor(Loc, Constructor);
}
} else if (Constructor->getInheritedConstructor()) {
DefineInheritingConstructor(Loc, Constructor);
}
} else if (CXXDestructorDecl *Destructor =
dyn_cast<CXXDestructorDecl>(Func)) {
Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
return;
DefineImplicitDefaultConstructor(Loc, Constructor);
} else if (Constructor->isCopyConstructor()) {
DefineImplicitCopyConstructor(Loc, Constructor);
} else if (Constructor->isMoveConstructor()) {
DefineImplicitMoveConstructor(Loc, Constructor);
DefineImplicitDestructor(Loc, Destructor);
}
} else if (Constructor->getInheritedConstructor()) {
DefineInheritingConstructor(Loc, Constructor);
}
} else if (CXXDestructorDecl *Destructor =
dyn_cast<CXXDestructorDecl>(Func)) {
Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
return;
DefineImplicitDestructor(Loc, Destructor);
if (Destructor->isVirtual() && getLangOpts().AppleKext)
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
if (MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
if (MethodDecl->isCopyAssignmentOperator())
DefineImplicitCopyAssignment(Loc, MethodDecl);
else if (MethodDecl->isMoveAssignmentOperator())
DefineImplicitMoveAssignment(Loc, MethodDecl);
}
} else if (isa<CXXConversionDecl>(MethodDecl) &&
MethodDecl->getParent()->isLambda()) {
CXXConversionDecl *Conversion =
cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
if (Conversion->isLambdaToBlockPointerConversion())
DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
else
DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
} else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
MarkVTableUsed(Loc, MethodDecl->getParent());
}
if (Destructor->isVirtual() && getLangOpts().AppleKext)
MarkVTableUsed(Loc, Destructor->getParent());
} else if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(Func)) {
if (MethodDecl->isOverloadedOperator() &&
MethodDecl->getOverloadedOperator() == OO_Equal) {
MethodDecl = cast<CXXMethodDecl>(MethodDecl->getFirstDecl());
if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
if (MethodDecl->isCopyAssignmentOperator())
DefineImplicitCopyAssignment(Loc, MethodDecl);
else if (MethodDecl->isMoveAssignmentOperator())
DefineImplicitMoveAssignment(Loc, MethodDecl);
}
} else if (isa<CXXConversionDecl>(MethodDecl) &&
MethodDecl->getParent()->isLambda()) {
CXXConversionDecl *Conversion =
cast<CXXConversionDecl>(MethodDecl->getFirstDecl());
if (Conversion->isLambdaToBlockPointerConversion())
DefineImplicitLambdaToBlockPointerConversion(Loc, Conversion);
else
DefineImplicitLambdaToFunctionPointerConversion(Loc, Conversion);
} else if (MethodDecl->isVirtual() && getLangOpts().AppleKext)
MarkVTableUsed(Loc, MethodDecl->getParent());
}

// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
TemplateSpecializationKind TSK =
Func->getTemplateSpecializationKindForInstantiation();
SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
bool FirstInstantiation = PointOfInstantiation.isInvalid();
if (FirstInstantiation) {
PointOfInstantiation = Loc;
Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
} else if (TSK != TSK_ImplicitInstantiation) {
// Use the point of use as the point of instantiation, instead of the
// point of explicit instantiation (which we track as the actual point
// of instantiation). This gives better backtraces in diagnostics.
PointOfInstantiation = Loc;
}
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
TemplateSpecializationKind TSK =
Func->getTemplateSpecializationKindForInstantiation();
SourceLocation PointOfInstantiation = Func->getPointOfInstantiation();
bool FirstInstantiation = PointOfInstantiation.isInvalid();
if (FirstInstantiation) {
PointOfInstantiation = Loc;
Func->setTemplateSpecializationKind(TSK, PointOfInstantiation);
} else if (TSK != TSK_ImplicitInstantiation) {
// Use the point of use as the point of instantiation, instead of the
// point of explicit instantiation (which we track as the actual point
// of instantiation). This gives better backtraces in diagnostics.
PointOfInstantiation = Loc;
}

if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
Func->isConstexpr()) {
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
CodeSynthesisContexts.size())
PendingLocalImplicitInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
else if (Func->isConstexpr())
// Do not defer instantiations of constexpr functions, to avoid the
// expression evaluator needing to call back into Sema if it sees a
// call to such a function.
InstantiateFunctionDefinition(PointOfInstantiation, Func);
else {
Func->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
// Notify the consumer that a function was implicitly instantiated.
Consumer.HandleCXXImplicitFunctionInstantiation(Func);
if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
Func->isConstexpr()) {
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
CodeSynthesisContexts.size())
PendingLocalImplicitInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
else if (Func->isConstexpr())
// Do not defer instantiations of constexpr functions, to avoid the
// expression evaluator needing to call back into Sema if it sees a
// call to such a function.
InstantiateFunctionDefinition(PointOfInstantiation, Func);
else {
Func->setInstantiationIsPending(true);
PendingInstantiations.push_back(
std::make_pair(Func, PointOfInstantiation));
// Notify the consumer that a function was implicitly instantiated.
Consumer.HandleCXXImplicitFunctionInstantiation(Func);
}
}
} else {
// Walk redefinitions, as some of them may be instantiable.
for (auto i : Func->redecls()) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
}
} else {
// Walk redefinitions, as some of them may be instantiable.
for (auto i : Func->redecls()) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
MarkFunctionReferenced(Loc, i, MightBeOdrUse);
}
}
});
}

// If this is the first "real" use, act on that.
Expand Down Expand Up @@ -16493,7 +16509,9 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
if (UsableInConstantExpr) {
// Do not defer instantiations of variables that could be used in a
// constant expression.
SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
SemaRef.runWithSufficientStackSpace(PointOfInstantiation, [&] {
SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var);
});
} else if (FirstInstantiation ||
isa<VarTemplateSpecializationDecl>(Var)) {
// FIXME: For a specialization of a variable template, we don't
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6242,8 +6242,11 @@ PerformConstructorInitialization(Sema &S,
// the definition for completely trivial constructors.
assert(Constructor->getParent() && "No parent class for constructor.");
if (Constructor->isDefaulted() && Constructor->isDefaultConstructor() &&
Constructor->isTrivial() && !Constructor->isUsed(false))
S.DefineImplicitDefaultConstructor(Loc, Constructor);
Constructor->isTrivial() && !Constructor->isUsed(false)) {
S.runWithSufficientStackSpace(Loc, [&] {
S.DefineImplicitDefaultConstructor(Loc, Constructor);
});
}
}

ExprResult CurInit((Expr *)nullptr);
Expand Down
56 changes: 38 additions & 18 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3088,8 +3088,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
SpecialMemberCache.InsertNode(Result, InsertPoint);

if (SM == CXXDestructor) {
if (RD->needsImplicitDestructor())
DeclareImplicitDestructor(RD);
if (RD->needsImplicitDestructor()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
DeclareImplicitDestructor(RD);
});
}
CXXDestructorDecl *DD = RD->getDestructor();
assert(DD && "record without a destructor");
Result->setMethod(DD);
Expand All @@ -3112,21 +3115,36 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
if (SM == CXXDefaultConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
NumArgs = 0;
if (RD->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(RD);
if (RD->needsImplicitDefaultConstructor()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
DeclareImplicitDefaultConstructor(RD);
});
}
} else {
if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) {
Name = Context.DeclarationNames.getCXXConstructorName(CanTy);
if (RD->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(RD);
if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(RD);
if (RD->needsImplicitCopyConstructor()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
DeclareImplicitCopyConstructor(RD);
});
}
if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveConstructor()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
DeclareImplicitMoveConstructor(RD);
});
}
} else {
Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
if (RD->needsImplicitCopyAssignment())
DeclareImplicitCopyAssignment(RD);
if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment())
DeclareImplicitMoveAssignment(RD);
if (RD->needsImplicitCopyAssignment()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
DeclareImplicitCopyAssignment(RD);
});
}
if (getLangOpts().CPlusPlus11 && RD->needsImplicitMoveAssignment()) {
runWithSufficientStackSpace(RD->getLocation(), [&] {
DeclareImplicitMoveAssignment(RD);
});
}
}

if (ConstArg)
Expand Down Expand Up @@ -3283,12 +3301,14 @@ CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class,
DeclContext::lookup_result Sema::LookupConstructors(CXXRecordDecl *Class) {
// If the implicit constructors have not yet been declared, do so now.
if (CanDeclareSpecialMemberFunction(Class)) {
if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
if (Class->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(Class);
if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class);
runWithSufficientStackSpace(Class->getLocation(), [&] {
if (Class->needsImplicitDefaultConstructor())
DeclareImplicitDefaultConstructor(Class);
if (Class->needsImplicitCopyConstructor())
DeclareImplicitCopyConstructor(Class);
if (getLangOpts().CPlusPlus11 && Class->needsImplicitMoveConstructor())
DeclareImplicitMoveConstructor(Class);
});
}

CanQualType T = Context.getCanonicalType(Context.getTypeDeclType(Class));
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/Stack.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
Expand Down
14 changes: 10 additions & 4 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4632,8 +4632,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,

// We might need to deduce the return type by instantiating the definition
// of the operator() function.
if (CallOp->getReturnType()->isUndeducedType())
InstantiateFunctionDefinition(Loc, CallOp);
if (CallOp->getReturnType()->isUndeducedType()) {
runWithSufficientStackSpace(Loc, [&] {
InstantiateFunctionDefinition(Loc, CallOp);
});
}
}

if (CallOp->isInvalidDecl())
Expand All @@ -4654,8 +4657,11 @@ bool Sema::DeduceReturnType(FunctionDecl *FD, SourceLocation Loc,
return false;
}

if (FD->getTemplateInstantiationPattern())
InstantiateFunctionDefinition(Loc, FD);
if (FD->getTemplateInstantiationPattern()) {
runWithSufficientStackSpace(Loc, [&] {
InstantiateFunctionDefinition(Loc, FD);
});
}

bool StillUndeduced = FD->getReturnType()->isUndeducedType();
if (StillUndeduced && Diagnose && !FD->isInvalidDecl()) {
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyDeclStackTrace.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Stack.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
Expand Down Expand Up @@ -365,6 +366,11 @@ void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) {

if (!Ctx.isInstantiationRecord())
++NonInstantiationEntries;

// Check to see if we're low on stack space. We can't do anything about this
// from here, but we can at least warn the user.
if (isStackNearlyExhausted())
warnStackExhausted(Ctx.PointOfInstantiation);
}

void Sema::popCodeSynthesisContext() {
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3413,7 +3413,11 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
if (D->isInvalidDecl())
return nullptr;

return Instantiator.Visit(D);
Decl *SubstD;
runWithSufficientStackSpace(D->getLocation(), [&] {
SubstD = Instantiator.Visit(D);
});
return SubstD;
}

/// Instantiates a nested template parameter list in the current
Expand Down
22 changes: 14 additions & 8 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7729,7 +7729,9 @@ void Sema::completeExprArrayBound(Expr *E) {
auto *Def = Var->getDefinition();
if (!Def) {
SourceLocation PointOfInstantiation = E->getExprLoc();
InstantiateVariableDefinition(PointOfInstantiation, Var);
runWithSufficientStackSpace(PointOfInstantiation, [&] {
InstantiateVariableDefinition(PointOfInstantiation, Var);
});
Def = Var->getDefinition();

// If we don't already have a point of instantiation, and we managed
Expand Down Expand Up @@ -8067,9 +8069,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
} else if (auto *ClassTemplateSpec =
dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
Diagnosed = InstantiateClassTemplateSpecialization(
Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
/*Complain=*/Diagnoser);
runWithSufficientStackSpace(Loc, [&] {
Diagnosed = InstantiateClassTemplateSpecialization(
Loc, ClassTemplateSpec, TSK_ImplicitInstantiation,
/*Complain=*/Diagnoser);
});
Instantiated = true;
}
} else {
Expand All @@ -8080,10 +8084,12 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// This record was instantiated from a class within a template.
if (MSI->getTemplateSpecializationKind() !=
TSK_ExplicitSpecialization) {
Diagnosed = InstantiateClass(Loc, RD, Pattern,
getTemplateInstantiationArgs(RD),
TSK_ImplicitInstantiation,
/*Complain=*/Diagnoser);
runWithSufficientStackSpace(Loc, [&] {
Diagnosed = InstantiateClass(Loc, RD, Pattern,
getTemplateInstantiationArgs(RD),
TSK_ImplicitInstantiation,
/*Complain=*/Diagnoser);
});
Instantiated = true;
}
}
Expand Down
3 changes: 2 additions & 1 deletion clang/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ llvm_canonicalize_cmake_booleans(
ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER
HAVE_LIBZ
LLVM_ENABLE_PER_TARGET_RUNTIME_DIR
LLVM_ENABLE_PLUGINS)
LLVM_ENABLE_PLUGINS
LLVM_ENABLE_THREADS)

configure_lit_site_cfg(
${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in
Expand Down
18 changes: 18 additions & 0 deletions clang/test/SemaTemplate/stack-exhaustion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// RUN: %clang_cc1 -verify %s
// REQUIRES: thread_support

// expected-warning@* 0-1{{stack nearly exhausted}}
// expected-note@* 0+{{}}

template<int N> struct X : X<N-1> {};
template<> struct X<0> {};
X<1000> x;

template<typename ...T> struct tuple {};
template<typename ...T> auto f(tuple<T...> t) -> decltype(f(tuple<T...>(t))) {} // expected-error {{exceeded maximum depth}}
void g() { f(tuple<int, int>()); }

int f(X<0>);
template<int N> auto f(X<N>) -> f(X<N-1>());

int k = f(X<1000>());
3 changes: 3 additions & 0 deletions clang/test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ def calculate_arch_features(arch_string):
if config.enable_backtrace:
config.available_features.add('backtrace')

if config.enable_threads:
config.available_features.add('thread_support')

# Check if we should allow outputs to console.
run_console_tests = int(lit_config.params.get('enable_console', '0'))
if run_console_tests != 0:
Expand Down
1 change: 1 addition & 0 deletions clang/test/lit.site.cfg.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ config.clang_examples = @CLANG_BUILD_EXAMPLES@
config.enable_shared = @ENABLE_SHARED@
config.enable_backtrace = @ENABLE_BACKTRACES@
config.enable_experimental_new_pass_manager = @ENABLE_EXPERIMENTAL_NEW_PASS_MANAGER@
config.enable_threads = @LLVM_ENABLE_THREADS@
config.host_arch = "@HOST_ARCH@"
config.python_executable = "@PYTHON_EXECUTABLE@"
config.use_z3_solver = lit_config.params.get('USE_Z3_SOLVER', "@USE_Z3_SOLVER@")
Expand Down
2 changes: 2 additions & 0 deletions clang/tools/driver/driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "clang/Driver/Driver.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/Stack.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
Expand Down Expand Up @@ -319,6 +320,7 @@ static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
}

int main(int argc_, const char **argv_) {
noteBottomOfStack();
llvm::InitLLVM X(argc_, argv_);
SmallVector<const char *, 256> argv(argv_, argv_ + argc_);

Expand Down