Skip to content

Commit f37eb75

Browse files
committed
[clang] add -fimplicit-constexpr flag (with same behaviour as GCC)
1 parent 6196b4e commit f37eb75

File tree

13 files changed

+339
-7
lines changed

13 files changed

+339
-7
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,6 +2418,9 @@ class FunctionDecl : public DeclaratorDecl,
24182418
bool isConstexpr() const {
24192419
return getConstexprKind() != ConstexprSpecKind::Unspecified;
24202420
}
2421+
/// Support for `-fimplicit-constexpr`
2422+
bool isConstexprOrImplicitlyCanBe(const LangOptions &LangOpts,
2423+
bool MustBeInlined = true) const;
24212424
void setConstexprKind(ConstexprSpecKind CSK) {
24222425
FunctionDeclBits.ConstexprKind = static_cast<uint64_t>(CSK);
24232426
}

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ def note_constexpr_lshift_discards : Note<"signed left shift discards bits">;
3232
def note_constexpr_invalid_function : Note<
3333
"%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
3434
"be used in a constant expression">;
35+
def note_constexpr_implicit_constexpr_must_be_inlined
36+
: Note<"non-inline function %0 is not implicitly constexpr">;
3537
def note_constexpr_invalid_inhctor : Note<
3638
"constructor inherited from base class %0 cannot be used in a "
3739
"constant expression; derived class cannot be implicitly initialized">;

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ EXTENSION(matrix_types, LangOpts.MatrixTypes)
316316
EXTENSION(matrix_types_scalar_division, true)
317317
EXTENSION(cxx_attributes_on_using_declarations, LangOpts.CPlusPlus11)
318318
EXTENSION(datasizeof, LangOpts.CPlusPlus)
319+
EXTENSION(cxx_implicit_constexpr, LangOpts.ImplicitConstexpr)
319320

320321
FEATURE(cxx_abi_relative_vtable, LangOpts.CPlusPlus && LangOpts.RelativeCXXABIVTables)
321322

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ BENIGN_LANGOPT(ArrowDepth, 32, 256,
413413
"maximum number of operator->s to follow")
414414
BENIGN_LANGOPT(InstantiationDepth, 32, 1024,
415415
"maximum template instantiation depth")
416+
COMPATIBLE_LANGOPT(ImplicitConstexpr, 1, 0, "make functions implicitly 'constexpr'")
416417
BENIGN_LANGOPT(ConstexprCallDepth, 32, 512,
417418
"maximum constexpr call depth")
418419
BENIGN_LANGOPT(ConstexprStepLimit, 32, 1048576,

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1991,6 +1991,12 @@ defm constant_cfstrings : BoolFOption<"constant-cfstrings",
19911991
"Disable creation of CodeFoundation-type constant strings">,
19921992
PosFlag<SetFalse>>;
19931993
def fconstant_string_class_EQ : Joined<["-"], "fconstant-string-class=">, Group<f_Group>;
1994+
def fimplicit_constexpr
1995+
: Joined<["-"], "fimplicit-constexpr">,
1996+
Group<f_Group>,
1997+
Visibility<[ClangOption, CC1Option]>,
1998+
HelpText<"All function declarations will be implicitly constexpr.">,
1999+
MarshallingInfoFlag<LangOpts<"ImplicitConstexpr">>;
19942000
def fconstexpr_depth_EQ : Joined<["-"], "fconstexpr-depth=">, Group<f_Group>,
19952001
Visibility<[ClangOption, CC1Option]>,
19962002
HelpText<"Set the maximum depth of recursive constexpr function calls">,

clang/lib/AST/Decl.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3242,6 +3242,27 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition,
32423242
return false;
32433243
}
32443244

3245+
bool FunctionDecl::isConstexprOrImplicitlyCanBe(const LangOptions &LangOpts,
3246+
bool MustBeInlined) const {
3247+
if (isConstexpr())
3248+
return true;
3249+
3250+
if (!LangOpts.ImplicitConstexpr)
3251+
return false;
3252+
3253+
// Constexpr function in C++11 couldn't contain anything other then return
3254+
// expression. It wouldn't make sense to allow it (GCC doesn't do it neither).
3255+
if (!LangOpts.CPlusPlus14)
3256+
return false;
3257+
3258+
// Free functions must be inlined, but sometimes we want to skip this check.
3259+
// And in order to keep logic on one place, the check is here.
3260+
if (MustBeInlined)
3261+
return isInlined();
3262+
3263+
return true;
3264+
}
3265+
32453266
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
32463267
if (!hasBody(Definition))
32473268
return nullptr;

clang/lib/AST/ExprConstant.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5968,8 +5968,9 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
59685968

59695969
// Can we evaluate this function call?
59705970
if (Definition && Body &&
5971-
(Definition->isConstexpr() || (Info.CurrentCall->CanEvalMSConstexpr &&
5972-
Definition->hasAttr<MSConstexprAttr>())))
5971+
(Definition->isConstexprOrImplicitlyCanBe(Info.Ctx.getLangOpts()) ||
5972+
(Info.CurrentCall->CanEvalMSConstexpr &&
5973+
Definition->hasAttr<MSConstexprAttr>())))
59735974
return true;
59745975

59755976
if (Info.getLangOpts().CPlusPlus11) {
@@ -5987,12 +5988,25 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
59875988
// FIXME: If DiagDecl is an implicitly-declared special member function
59885989
// or an inheriting constructor, we should be much more explicit about why
59895990
// it's not constexpr.
5990-
if (CD && CD->isInheritingConstructor())
5991+
if (CD && CD->isInheritingConstructor()) {
59915992
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_inhctor, 1)
59925993
<< CD->getInheritedConstructor().getConstructor()->getParent();
5993-
else
5994+
5995+
} else if (Definition && !DiagDecl->isInlined() &&
5996+
Info.Ctx.getLangOpts().ImplicitConstexpr) {
5997+
Info.FFDiag(CallLoc,
5998+
diag::note_constexpr_implicit_constexpr_must_be_inlined)
5999+
<< DiagDecl;
6000+
6001+
} else {
6002+
// Using implicit constexpr check here, so we see a missing body as main
6003+
// problem and not missing constexpr with -fimplicit-constexpr.
59946004
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1)
5995-
<< DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
6005+
<< DiagDecl->isConstexprOrImplicitlyCanBe(Info.Ctx.getLangOpts(),
6006+
false)
6007+
<< (bool)CD << DiagDecl;
6008+
}
6009+
59966010
Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
59976011
} else {
59986012
Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6612,6 +6612,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
66126612
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_depth_EQ);
66136613
Args.AddLastArg(CmdArgs, options::OPT_fconstexpr_steps_EQ);
66146614

6615+
if (types::isCXX(InputType))
6616+
Args.AddLastArg(CmdArgs, options::OPT_fimplicit_constexpr);
6617+
66156618
Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library);
66166619

66176620
if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter))

clang/lib/Frontend/InitPreprocessor.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,9 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
779779

780780
// TODO: Final number?
781781
Builder.defineMacro("__cpp_type_aware_allocators", "202500L");
782+
783+
if (LangOpts.ImplicitConstexpr) // same value as GCC
784+
Builder.defineMacro("__cpp_implicit_constexpr", "20211111");
782785
}
783786

784787
/// InitializeOpenCLFeatureTestMacros - Define OpenCL macros based on target

clang/lib/Sema/SemaExpr.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18384,16 +18384,18 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
1838418384
}
1838518385

1838618386
if (FirstInstantiation || TSK != TSK_ImplicitInstantiation ||
18387-
Func->isConstexpr()) {
18387+
Func->isConstexprOrImplicitlyCanBe(getLangOpts())) {
1838818388
if (isa<CXXRecordDecl>(Func->getDeclContext()) &&
1838918389
cast<CXXRecordDecl>(Func->getDeclContext())->isLocalClass() &&
1839018390
CodeSynthesisContexts.size())
1839118391
PendingLocalImplicitInstantiations.push_back(
1839218392
std::make_pair(Func, PointOfInstantiation));
18393-
else if (Func->isConstexpr())
18393+
else if (Func->isConstexprOrImplicitlyCanBe(getLangOpts()))
1839418394
// Do not defer instantiations of constexpr functions, to avoid the
1839518395
// expression evaluator needing to call back into Sema if it sees a
1839618396
// call to such a function.
18397+
// (When -fimplicit-instantiation is enabled, all functions are
18398+
// implicitly constexpr)
1839718399
InstantiateFunctionDefinition(PointOfInstantiation, Func);
1839818400
else {
1839918401
Func->setInstantiationIsPending(true);

0 commit comments

Comments
 (0)