forked from OSchip/llvm-project
[ASTImporter] Support functions with placeholder return types ...
Summary: Support functions with placeholder return types even in cases when the type is declared in the body of the function. Example: auto f() { struct X{}; return X(); } Reviewers: balazske, a_sidorin, a.sidorin, shafik Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, teemperor, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D70819
This commit is contained in:
parent
11b2b2f4b1
commit
25234fd69e
|
@ -648,6 +648,11 @@ namespace clang {
|
||||||
|
|
||||||
Expected<FunctionDecl *> FindFunctionTemplateSpecialization(
|
Expected<FunctionDecl *> FindFunctionTemplateSpecialization(
|
||||||
FunctionDecl *FromFD);
|
FunctionDecl *FromFD);
|
||||||
|
|
||||||
|
// Returns true if the given function has a placeholder return type and
|
||||||
|
// that type is declared inside the body of the function.
|
||||||
|
// E.g. auto f() { struct X{}; return X(); }
|
||||||
|
bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename InContainerTy>
|
template <typename InContainerTy>
|
||||||
|
@ -1547,6 +1552,10 @@ Error ASTNodeImporter::ImportDeclParts(
|
||||||
DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) {
|
DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) {
|
||||||
// Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop.
|
// Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop.
|
||||||
// example: int struct_in_proto(struct data_t{int a;int b;} *d);
|
// example: int struct_in_proto(struct data_t{int a;int b;} *d);
|
||||||
|
// FIXME: We could support these constructs by importing a different type of
|
||||||
|
// this parameter and by importing the original type of the parameter only
|
||||||
|
// after the FunctionDecl is created. See
|
||||||
|
// VisitFunctionDecl::UsedDifferentProtoType.
|
||||||
DeclContext *OrigDC = D->getDeclContext();
|
DeclContext *OrigDC = D->getDeclContext();
|
||||||
FunctionDecl *FunDecl;
|
FunctionDecl *FunDecl;
|
||||||
if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) &&
|
if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) &&
|
||||||
|
@ -3005,6 +3014,46 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the given D has a DeclContext up to the TranslationUnitDecl
|
||||||
|
// which is equal to the given DC.
|
||||||
|
bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
|
||||||
|
const DeclContext *DCi = D->getDeclContext();
|
||||||
|
while (DCi != D->getTranslationUnitDecl()) {
|
||||||
|
if (DCi == DC)
|
||||||
|
return true;
|
||||||
|
DCi = DCi->getParent();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
|
||||||
|
QualType FromTy = D->getType();
|
||||||
|
const FunctionProtoType *FromFPT = FromTy->getAs<FunctionProtoType>();
|
||||||
|
assert(FromFPT && "Must be called on FunctionProtoType");
|
||||||
|
if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) {
|
||||||
|
QualType DeducedT = AutoT->getDeducedType();
|
||||||
|
if (const RecordType *RecordT =
|
||||||
|
DeducedT.isNull() ? nullptr : dyn_cast<RecordType>(DeducedT)) {
|
||||||
|
RecordDecl *RD = RecordT->getDecl();
|
||||||
|
assert(RD);
|
||||||
|
if (isAncestorDeclContextOf(D, RD)) {
|
||||||
|
assert(RD->getLexicalDeclContext() == RD->getDeclContext());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (const TypedefType *TypedefT =
|
||||||
|
dyn_cast<TypedefType>(FromFPT->getReturnType())) {
|
||||||
|
TypedefNameDecl *TD = TypedefT->getDecl();
|
||||||
|
assert(TD);
|
||||||
|
if (isAncestorDeclContextOf(D, TD)) {
|
||||||
|
assert(TD->getLexicalDeclContext() == TD->getDeclContext());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
|
|
||||||
SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D);
|
SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D);
|
||||||
|
@ -3128,22 +3177,37 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
return std::move(Err);
|
return std::move(Err);
|
||||||
|
|
||||||
QualType FromTy = D->getType();
|
QualType FromTy = D->getType();
|
||||||
bool usedDifferentExceptionSpec = false;
|
// Set to true if we do not import the type of the function as is. There are
|
||||||
|
// cases when the original type would result in an infinite recursion during
|
||||||
if (const auto *FromFPT = D->getType()->getAs<FunctionProtoType>()) {
|
// the import. To avoid an infinite recursion when importing, we create the
|
||||||
|
// FunctionDecl with a simplified function type and update it only after the
|
||||||
|
// relevant AST nodes are already imported.
|
||||||
|
bool UsedDifferentProtoType = false;
|
||||||
|
if (const auto *FromFPT = FromTy->getAs<FunctionProtoType>()) {
|
||||||
|
QualType FromReturnTy = FromFPT->getReturnType();
|
||||||
|
// Functions with auto return type may define a struct inside their body
|
||||||
|
// and the return type could refer to that struct.
|
||||||
|
// E.g.: auto foo() { struct X{}; return X(); }
|
||||||
|
// To avoid an infinite recursion when importing, create the FunctionDecl
|
||||||
|
// with a simplified return type.
|
||||||
|
if (hasAutoReturnTypeDeclaredInside(D)) {
|
||||||
|
FromReturnTy = Importer.getFromContext().VoidTy;
|
||||||
|
UsedDifferentProtoType = true;
|
||||||
|
}
|
||||||
FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
|
FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo();
|
||||||
// FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the
|
// FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the
|
||||||
// FunctionDecl that we are importing the FunctionProtoType for.
|
// FunctionDecl that we are importing the FunctionProtoType for.
|
||||||
// To avoid an infinite recursion when importing, create the FunctionDecl
|
// To avoid an infinite recursion when importing, create the FunctionDecl
|
||||||
// with a simplified function type and update it afterwards.
|
// with a simplified function type.
|
||||||
if (FromEPI.ExceptionSpec.SourceDecl ||
|
if (FromEPI.ExceptionSpec.SourceDecl ||
|
||||||
FromEPI.ExceptionSpec.SourceTemplate ||
|
FromEPI.ExceptionSpec.SourceTemplate ||
|
||||||
FromEPI.ExceptionSpec.NoexceptExpr) {
|
FromEPI.ExceptionSpec.NoexceptExpr) {
|
||||||
FunctionProtoType::ExtProtoInfo DefaultEPI;
|
FunctionProtoType::ExtProtoInfo DefaultEPI;
|
||||||
FromTy = Importer.getFromContext().getFunctionType(
|
FromEPI = DefaultEPI;
|
||||||
FromFPT->getReturnType(), FromFPT->getParamTypes(), DefaultEPI);
|
UsedDifferentProtoType = true;
|
||||||
usedDifferentExceptionSpec = true;
|
|
||||||
}
|
}
|
||||||
|
FromTy = Importer.getFromContext().getFunctionType(
|
||||||
|
FromReturnTy, FromFPT->getParamTypes(), FromEPI);
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType T;
|
QualType T;
|
||||||
|
@ -3277,14 +3341,6 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usedDifferentExceptionSpec) {
|
|
||||||
// Update FunctionProtoType::ExtProtoInfo.
|
|
||||||
if (ExpectedType TyOrErr = import(D->getType()))
|
|
||||||
ToFunction->setType(*TyOrErr);
|
|
||||||
else
|
|
||||||
return TyOrErr.takeError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Import the describing template function, if any.
|
// Import the describing template function, if any.
|
||||||
if (FromFT) {
|
if (FromFT) {
|
||||||
auto ToFTOrErr = import(FromFT);
|
auto ToFTOrErr = import(FromFT);
|
||||||
|
@ -3316,6 +3372,14 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
return std::move(Err);
|
return std::move(Err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Import and set the original type in case we used another type.
|
||||||
|
if (UsedDifferentProtoType) {
|
||||||
|
if (ExpectedType TyOrErr = import(D->getType()))
|
||||||
|
ToFunction->setType(*TyOrErr);
|
||||||
|
else
|
||||||
|
return TyOrErr.takeError();
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Other bits to merge?
|
// FIXME: Other bits to merge?
|
||||||
|
|
||||||
// If it is a template, import all related things.
|
// If it is a template, import all related things.
|
||||||
|
|
|
@ -10,9 +10,11 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
|
|
||||||
#include "clang/AST/DeclContextInternals.h"
|
#include "clang/AST/DeclContextInternals.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#include "ASTImporterFixtures.h"
|
#include "ASTImporterFixtures.h"
|
||||||
#include "MatchVerifier.h"
|
#include "MatchVerifier.h"
|
||||||
|
@ -5623,6 +5625,188 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImplicitlyDeclareSelf) {
|
||||||
EXPECT_TRUE(ToMethod->getSelfDecl() != nullptr);
|
EXPECT_TRUE(ToMethod->getSelfDecl() != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ImportAutoFunctions : ASTImporterOptionSpecificTestBase {};
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithTypedefDeclaredInside) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto X = [](long l) {
|
||||||
|
using int_type = long;
|
||||||
|
auto dur = 13;
|
||||||
|
return static_cast<int_type>(dur);
|
||||||
|
};
|
||||||
|
)",
|
||||||
|
Lang_CXX14, "input0.cc");
|
||||||
|
CXXMethodDecl *From =
|
||||||
|
FirstDeclMatcher<CXXMethodDecl>().match(FromTU, cxxMethodDecl());
|
||||||
|
|
||||||
|
// Explicitly set the return type of the lambda's operator() to the TypeAlias.
|
||||||
|
// Normally the return type would be the built-in 'long' type. However, there
|
||||||
|
// are cases when Clang does not use the canonical type and the TypeAlias is
|
||||||
|
// used. I could not create such an AST from regular source code, it requires
|
||||||
|
// some special state in the preprocessor. I've found such an AST when Clang
|
||||||
|
// parsed libcxx/src/filesystem/directory_iterator.cpp, but could not reduce
|
||||||
|
// that with creduce, because after preprocessing, the AST no longer
|
||||||
|
// contained the TypeAlias as a return type of the lambda.
|
||||||
|
ASTContext &Ctx = From->getASTContext();
|
||||||
|
TypeAliasDecl *FromTA =
|
||||||
|
FirstDeclMatcher<TypeAliasDecl>().match(FromTU, typeAliasDecl());
|
||||||
|
QualType TT = Ctx.getTypedefType(FromTA);
|
||||||
|
const FunctionProtoType *FPT = cast<FunctionProtoType>(From->getType());
|
||||||
|
QualType NewFunType =
|
||||||
|
Ctx.getFunctionType(TT, FPT->getParamTypes(), FPT->getExtProtoInfo());
|
||||||
|
From->setType(NewFunType);
|
||||||
|
|
||||||
|
CXXMethodDecl *To = Import(From, Lang_CXX14);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<TypedefType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredInside) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto foo() {
|
||||||
|
struct X {};
|
||||||
|
return X();
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX14, "input0.cc");
|
||||||
|
FunctionDecl *From =
|
||||||
|
FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl());
|
||||||
|
|
||||||
|
FunctionDecl *To = Import(From, Lang_CXX14);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredInside2) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto foo() {
|
||||||
|
struct X {};
|
||||||
|
return X();
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX14, "input0.cc");
|
||||||
|
FunctionDecl *From =
|
||||||
|
FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl());
|
||||||
|
|
||||||
|
// This time import the type directly.
|
||||||
|
QualType ToT = ImportType(From->getType(), From, Lang_CXX14);
|
||||||
|
const FunctionProtoType *FPT = cast<FunctionProtoType>(ToT);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(FPT->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithTypedefToStructDeclaredInside) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto foo() {
|
||||||
|
struct X {};
|
||||||
|
using Y = X;
|
||||||
|
return Y();
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX14, "input0.cc");
|
||||||
|
FunctionDecl *From =
|
||||||
|
FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl());
|
||||||
|
|
||||||
|
FunctionDecl *To = Import(From, Lang_CXX14);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithStructDeclaredNestedInside) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto foo() {
|
||||||
|
struct X { struct Y{}; };
|
||||||
|
return X::Y();
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX14, "input0.cc");
|
||||||
|
FunctionDecl *From =
|
||||||
|
FirstDeclMatcher<FunctionDecl>().match(FromTU, functionDecl());
|
||||||
|
|
||||||
|
FunctionDecl *To = Import(From, Lang_CXX14);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithInternalLambdaType) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto f() {
|
||||||
|
auto l = []() {
|
||||||
|
struct X {};
|
||||||
|
return X();
|
||||||
|
};
|
||||||
|
return l();
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX17, "input0.cc");
|
||||||
|
FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
|
||||||
|
FromTU, functionDecl(hasName("f")));
|
||||||
|
|
||||||
|
FunctionDecl *To = Import(From, Lang_CXX17);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithTypeInIf) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto f() {
|
||||||
|
if (struct X {} x; true)
|
||||||
|
return X();
|
||||||
|
else
|
||||||
|
return X();
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX17, "input0.cc");
|
||||||
|
FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
|
||||||
|
FromTU, functionDecl(hasName("f")));
|
||||||
|
|
||||||
|
FunctionDecl *To = Import(From, Lang_CXX17);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithTypeInFor) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto f() {
|
||||||
|
for (struct X {} x;;)
|
||||||
|
return X();
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX17, "input0.cc");
|
||||||
|
FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
|
||||||
|
FromTU, functionDecl(hasName("f")));
|
||||||
|
|
||||||
|
FunctionDecl *To = Import(From, Lang_CXX17);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(ImportAutoFunctions, ReturnWithTypeInSwitch) {
|
||||||
|
Decl *FromTU = getTuDecl(
|
||||||
|
R"(
|
||||||
|
auto f() {
|
||||||
|
switch (struct X {} x; 10) {
|
||||||
|
case 10:
|
||||||
|
return X();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)",
|
||||||
|
Lang_CXX17, "input0.cc");
|
||||||
|
FunctionDecl *From = FirstDeclMatcher<FunctionDecl>().match(
|
||||||
|
FromTU, functionDecl(hasName("f")));
|
||||||
|
|
||||||
|
FunctionDecl *To = Import(From, Lang_CXX17);
|
||||||
|
EXPECT_TRUE(To);
|
||||||
|
EXPECT_TRUE(isa<AutoType>(To->getReturnType()));
|
||||||
|
}
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
|
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest,
|
||||||
DefaultTestValuesForRunOptions, );
|
DefaultTestValuesForRunOptions, );
|
||||||
|
|
||||||
|
@ -5650,6 +5834,9 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, RedirectingImporterTest,
|
||||||
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctions,
|
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctions,
|
||||||
DefaultTestValuesForRunOptions, );
|
DefaultTestValuesForRunOptions, );
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportAutoFunctions,
|
||||||
|
DefaultTestValuesForRunOptions, );
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctionTemplates,
|
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportFunctionTemplates,
|
||||||
DefaultTestValuesForRunOptions, );
|
DefaultTestValuesForRunOptions, );
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,9 @@ ArgVector getBasicRunOptionsForLanguage(Language Lang) {
|
||||||
case Lang_CXX14:
|
case Lang_CXX14:
|
||||||
BasicArgs = {"-std=c++14", "-frtti"};
|
BasicArgs = {"-std=c++14", "-frtti"};
|
||||||
break;
|
break;
|
||||||
|
case Lang_CXX17:
|
||||||
|
BasicArgs = {"-std=c++17", "-frtti"};
|
||||||
|
break;
|
||||||
case Lang_CXX2a:
|
case Lang_CXX2a:
|
||||||
BasicArgs = {"-std=c++2a", "-frtti"};
|
BasicArgs = {"-std=c++2a", "-frtti"};
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum Language {
|
||||||
Lang_CXX,
|
Lang_CXX,
|
||||||
Lang_CXX11,
|
Lang_CXX11,
|
||||||
Lang_CXX14,
|
Lang_CXX14,
|
||||||
|
Lang_CXX17,
|
||||||
Lang_CXX2a,
|
Lang_CXX2a,
|
||||||
Lang_OpenCL,
|
Lang_OpenCL,
|
||||||
Lang_OBJCXX
|
Lang_OBJCXX
|
||||||
|
|
|
@ -108,6 +108,10 @@ testing::AssertionResult MatchVerifier<NodeType>::match(
|
||||||
Args.push_back("-std=c++14");
|
Args.push_back("-std=c++14");
|
||||||
FileName = "input.cc";
|
FileName = "input.cc";
|
||||||
break;
|
break;
|
||||||
|
case Lang_CXX17:
|
||||||
|
Args.push_back("-std=c++17");
|
||||||
|
FileName = "input.cc";
|
||||||
|
break;
|
||||||
case Lang_CXX2a:
|
case Lang_CXX2a:
|
||||||
Args.push_back("-std=c++2a");
|
Args.push_back("-std=c++2a");
|
||||||
FileName = "input.cc";
|
FileName = "input.cc";
|
||||||
|
|
Loading…
Reference in New Issue