r291318 - PR23135: Don't instantiate constexpr functions referenced in unevaluated operands where possible.
Mehdi Amini via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 22 23:31:32 PST 2017
Hi Richard,
I have a link failure in WebKit following this patch, the move-assign operator for an nested class isn’t emitted (IRGen) in some context where it is needed.
I’m working on running creduce the test-case which is pretty large, but in case it rings a bell, I let you know already.
—
Mehdi
> On Jan 6, 2017, at 4:48 PM, Richard Smith via cfe-commits <cfe-commits at lists.llvm.org> wrote:
>
> Author: rsmith
> Date: Fri Jan 6 18:48:55 2017
> New Revision: 291318
>
> URL: http://llvm.org/viewvc/llvm-project?rev=291318&view=rev
> Log:
> PR23135: Don't instantiate constexpr functions referenced in unevaluated operands where possible.
>
> This implements something like the current direction of DR1581: we use a narrow
> syntactic check to determine the set of places where a constant expression
> could be evaluated, and only instantiate a constexpr function or variable if
> it's referenced in one of those contexts, or is odr-used.
>
> It's not yet clear whether this is the right set of syntactic locations; we
> currently consider all contexts within templates that would result in odr-uses
> after instantiation, and contexts within list-initialization (narrowing
> conversions take another victim...), as requiring instantiation. We could in
> principle restrict the former cases more (only const integral / reference
> variable initializers, and contexts in which a constant expression is required,
> perhaps). However, this is sufficient to allow us to accept libstdc++ code,
> which relies on GCC's behavior (which appears to be somewhat similar to this
> approach).
>
> Modified:
> cfe/trunk/include/clang/Sema/Sema.h
> cfe/trunk/lib/Parse/ParseInit.cpp
> cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> cfe/trunk/lib/Sema/SemaExpr.cpp
> cfe/trunk/lib/Sema/SemaExprMember.cpp
> cfe/trunk/lib/Sema/SemaInit.cpp
> cfe/trunk/lib/Sema/SemaLambda.cpp
> cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
> cfe/trunk/test/CXX/temp/temp.param/p5.cpp
> cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
> cfe/trunk/test/SemaCXX/member-init.cpp
> cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp
> cfe/trunk/test/SemaTemplate/default-arguments-cxx0x.cpp
> cfe/trunk/test/SemaTemplate/instantiate-init.cpp
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Fri Jan 6 18:48:55 2017
> @@ -807,6 +807,12 @@ public:
> /// run time.
> Unevaluated,
>
> + /// \brief The current expression occurs within a braced-init-list within
> + /// an unevaluated operand. This is mostly like a regular unevaluated
> + /// context, except that we still instantiate constexpr functions that are
> + /// referenced here so that we can perform narrowing checks correctly.
> + UnevaluatedList,
> +
> /// \brief The current expression occurs within a discarded statement.
> /// This behaves largely similarly to an unevaluated operand in preventing
> /// definitions from being required, but not in other ways.
> @@ -899,7 +905,8 @@ public:
> MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx);
>
> bool isUnevaluated() const {
> - return Context == Unevaluated || Context == UnevaluatedAbstract;
> + return Context == Unevaluated || Context == UnevaluatedAbstract ||
> + Context == UnevaluatedList;
> }
> };
>
> @@ -10194,6 +10201,22 @@ public:
> IsDecltype);
> }
>
> + enum InitListTag { InitList };
> + EnterExpressionEvaluationContext(Sema &Actions, InitListTag,
> + bool ShouldEnter = true)
> + : Actions(Actions), Entered(false) {
> + // In C++11 onwards, narrowing checks are performed on the contents of
> + // braced-init-lists, even when they occur within unevaluated operands.
> + // Therefore we still need to instantiate constexpr functions used in such
> + // a context.
> + if (ShouldEnter && Actions.isUnevaluatedContext() &&
> + Actions.getLangOpts().CPlusPlus11) {
> + Actions.PushExpressionEvaluationContext(Sema::UnevaluatedList, nullptr,
> + false);
> + Entered = true;
> + }
> + }
> +
> ~EnterExpressionEvaluationContext() {
> if (Entered)
> Actions.PopExpressionEvaluationContext();
>
> Modified: cfe/trunk/lib/Parse/ParseInit.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseInit.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseInit.cpp Fri Jan 6 18:48:55 2017
> @@ -404,6 +404,10 @@ ExprResult Parser::ParseBraceInitializer
> return Actions.ActOnInitList(LBraceLoc, None, ConsumeBrace());
> }
>
> + // Enter an appropriate expression evaluation context for an initializer list.
> + EnterExpressionEvaluationContext EnterContext(
> + Actions, EnterExpressionEvaluationContext::InitList);
> +
> bool InitExprsOk = true;
>
> while (1) {
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Jan 6 18:48:55 2017
> @@ -9828,9 +9828,14 @@ Sema::ComputeDefaultedDefaultCtorExcepti
> }
>
> // Field constructors.
> - for (const auto *F : ClassDecl->fields()) {
> + for (auto *F : ClassDecl->fields()) {
> if (F->hasInClassInitializer()) {
> - if (Expr *E = F->getInClassInitializer())
> + Expr *E = F->getInClassInitializer();
> + if (!E)
> + // FIXME: It's a little wasteful to build and throw away a
> + // CXXDefaultInitExpr here.
> + E = BuildCXXDefaultInitExpr(Loc, F).get();
> + if (E)
> ExceptSpec.CalledExpr(E);
> } else if (const RecordType *RecordTy
> = Context.getBaseElementType(F->getType())->getAs<RecordType>()) {
> @@ -12291,6 +12296,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr
> if (Field->getInClassInitializer())
> return CXXDefaultInitExpr::Create(Context, Loc, Field);
>
> + // If we might have already tried and failed to instantiate, don't try again.
> + if (Field->isInvalidDecl())
> + return ExprError();
> +
> // Maybe we haven't instantiated the in-class initializer. Go check the
> // pattern FieldDecl to see if it has one.
> CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent());
> @@ -12320,8 +12329,11 @@ ExprResult Sema::BuildCXXDefaultInitExpr
> }
>
> if (InstantiateInClassInitializer(Loc, Field, Pattern,
> - getTemplateInstantiationArgs(Field)))
> + getTemplateInstantiationArgs(Field))) {
> + // Don't diagnose this again.
> + Field->setInvalidDecl();
> return ExprError();
> + }
> return CXXDefaultInitExpr::Create(Context, Loc, Field);
> }
>
> @@ -12344,6 +12356,8 @@ ExprResult Sema::BuildCXXDefaultInitExpr
> << OutermostClass << Field;
> Diag(Field->getLocEnd(), diag::note_in_class_initializer_not_yet_parsed);
>
> + // Don't diagnose this again.
> + Field->setInvalidDecl();
> return ExprError();
> }
>
>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Jan 6 18:48:55 2017
> @@ -13150,41 +13150,63 @@ ExprResult Sema::HandleExprEvaluationCon
> return TransformToPotentiallyEvaluated(E);
> }
>
> -static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
> - // Do not mark anything as "used" within a dependent context; wait for
> - // an instantiation.
> - if (SemaRef.CurContext->isDependentContext())
> - return false;
> -
> +/// Are we within a context in which some evaluation could be performed (be it
> +/// constant evaluation or runtime evaluation)? Sadly, this notion is not quite
> +/// captured by C++'s idea of an "unevaluated context".
> +static bool isEvaluatableContext(Sema &SemaRef) {
> switch (SemaRef.ExprEvalContexts.back().Context) {
> case Sema::Unevaluated:
> case Sema::UnevaluatedAbstract:
> - // We are in an expression that is not potentially evaluated; do nothing.
> - // (Depending on how you read the standard, we actually do need to do
> - // something here for null pointer constants, but the standard's
> - // definition of a null pointer constant is completely crazy.)
> + case Sema::DiscardedStatement:
> + // Expressions in this context are never evaluated.
> return false;
>
> + case Sema::UnevaluatedList:
> + case Sema::ConstantEvaluated:
> + case Sema::PotentiallyEvaluated:
> + // Expressions in this context could be evaluated.
> + return true;
> +
> + case Sema::PotentiallyEvaluatedIfUsed:
> + // Referenced declarations will only be used if the construct in the
> + // containing expression is used, at which point we'll be given another
> + // turn to mark them.
> + return false;
> + }
> + llvm_unreachable("Invalid context");
> +}
> +
> +/// Are we within a context in which references to resolved functions or to
> +/// variables result in odr-use?
> +static bool isOdrUseContext(Sema &SemaRef, bool SkipDependentUses = true) {
> + // An expression in a template is not really an expression until it's been
> + // instantiated, so it doesn't trigger odr-use.
> + if (SkipDependentUses && SemaRef.CurContext->isDependentContext())
> + return false;
> +
> + switch (SemaRef.ExprEvalContexts.back().Context) {
> + case Sema::Unevaluated:
> + case Sema::UnevaluatedList:
> + case Sema::UnevaluatedAbstract:
> case Sema::DiscardedStatement:
> - // These are technically a potentially evaluated but they have the effect
> - // of suppressing use marking.
> return false;
>
> case Sema::ConstantEvaluated:
> case Sema::PotentiallyEvaluated:
> - // We are in a potentially evaluated expression (or a constant-expression
> - // in C++03); we need to do implicit template instantiation, implicitly
> - // define class members, and mark most declarations as used.
> return true;
>
> case Sema::PotentiallyEvaluatedIfUsed:
> - // Referenced declarations will only be used if the construct in the
> - // containing expression is used.
> return false;
> }
> llvm_unreachable("Invalid context");
> }
>
> +static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) {
> + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
> + return Func->isConstexpr() &&
> + (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided()));
> +}
> +
> /// \brief Mark a function referenced, and check whether it is odr-used
> /// (C++ [basic.def.odr]p2, C99 6.9p3)
> void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
> @@ -13200,7 +13222,7 @@ void Sema::MarkFunctionReferenced(Source
> //
> // We (incorrectly) mark overload resolution as an unevaluated context, so we
> // can just check that here.
> - bool OdrUse = MightBeOdrUse && IsPotentiallyEvaluatedContext(*this);
> + bool OdrUse = MightBeOdrUse && isOdrUseContext(*this);
>
> // Determine whether we require a function definition to exist, per
> // C++11 [temp.inst]p3:
> @@ -13209,27 +13231,11 @@ void Sema::MarkFunctionReferenced(Source
> // specialization is implicitly instantiated when the specialization is
> // referenced in a context that requires a function definition to exist.
> //
> - // We consider constexpr function templates to be referenced in a context
> - // that requires a definition to exist whenever they are referenced.
> - //
> - // FIXME: This instantiates constexpr functions too frequently. If this is
> - // really an unevaluated context (and we're not just in the definition of a
> - // function template or overload resolution or other cases which we
> - // incorrectly consider to be unevaluated contexts), and we're not in a
> - // subexpression which we actually need to evaluate (for instance, a
> - // template argument, array bound or an expression in a braced-init-list),
> - // we are not permitted to instantiate this constexpr function definition.
> - //
> - // FIXME: This also implicitly defines special members too frequently. They
> - // are only supposed to be implicitly defined if they are odr-used, but they
> - // are not odr-used from constant expressions in unevaluated contexts.
> - // However, they cannot be referenced if they are deleted, and they are
> - // deleted whenever the implicit definition of the special member would
> - // fail (with very few exceptions).
> - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
> + // That is either when this is an odr-use, or when a usage of a constexpr
> + // function occurs within an evaluatable context.
> bool NeedDefinition =
> - OdrUse || (Func->isConstexpr() && (Func->isImplicitlyInstantiable() ||
> - (MD && !MD->isUserProvided())));
> + OdrUse || (isEvaluatableContext(*this) &&
> + isImplicitlyDefinableConstexprFunction(Func));
>
> // C++14 [temp.expl.spec]p6:
> // If a template [...] is explicitly specialized then that specialization
> @@ -14122,13 +14128,12 @@ static void DoMarkVarDeclReferenced(Sema
> "Invalid Expr argument to DoMarkVarDeclReferenced");
> Var->setReferenced();
>
> - if (SemaRef.isUnevaluatedContext())
> - return;
> -
> TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind();
> - bool MarkODRUsed = IsPotentiallyEvaluatedContext(SemaRef);
> +
> + bool OdrUseContext = isOdrUseContext(SemaRef);
> bool NeedDefinition =
> - MarkODRUsed || Var->isUsableInConstantExpressions(SemaRef.Context);
> + OdrUseContext || (isEvaluatableContext(SemaRef) &&
> + Var->isUsableInConstantExpressions(SemaRef.Context));
>
> VarTemplateSpecializationDecl *VarSpec =
> dyn_cast<VarTemplateSpecializationDecl>(Var);
> @@ -14193,18 +14198,20 @@ static void DoMarkVarDeclReferenced(Sema
> // Note that we use the C++11 definition everywhere because nothing in
> // C++03 depends on whether we get the C++03 version correct. The second
> // part does not apply to references, since they are not objects.
> - if (MarkODRUsed && E && IsVariableAConstantExpression(Var, SemaRef.Context)) {
> + if (OdrUseContext && E &&
> + IsVariableAConstantExpression(Var, SemaRef.Context)) {
> // A reference initialized by a constant expression can never be
> // odr-used, so simply ignore it.
> if (!Var->getType()->isReferenceType())
> SemaRef.MaybeODRUseExprs.insert(E);
> - } else if (MarkODRUsed) {
> + } else if (OdrUseContext) {
> MarkVarDeclODRUsed(Var, Loc, SemaRef,
> /*MaxFunctionScopeIndex ptr*/ nullptr);
> - } else {
> - // If we don't yet know whether this context is going to end up being an
> - // evaluated context, and we're referencing a variable from an enclosing
> - // scope, add a potential capture.
> + } else if (isOdrUseContext(SemaRef, /*SkipDependentUses*/false)) {
> + // If this is a dependent context, we don't need to mark variables as
> + // odr-used, but we may still need to track them for lambda capture.
> + // FIXME: Do we also need to do this inside dependent typeid expressions
> + // (which are modeled as unevaluated at this point)?
> const bool RefersToEnclosingScope =
> (SemaRef.CurContext != Var->getDeclContext() &&
> Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage());
> @@ -14321,9 +14328,13 @@ void Sema::MarkAnyDeclReferenced(SourceL
> }
>
> namespace {
> - // Mark all of the declarations referenced
> + // Mark all of the declarations used by a type as referenced.
> // FIXME: Not fully implemented yet! We need to have a better understanding
> - // of when we're entering
> + // of when we're entering a context we should not recurse into.
> + // FIXME: This is and EvaluatedExprMarker are more-or-less equivalent to
> + // TreeTransforms rebuilding the type in a new context. Rather than
> + // duplicating the TreeTransform logic, we should consider reusing it here.
> + // Currently that causes problems when rebuilding LambdaExprs.
> class MarkReferencedDecls : public RecursiveASTVisitor<MarkReferencedDecls> {
> Sema &S;
> SourceLocation Loc;
> @@ -14462,6 +14473,7 @@ bool Sema::DiagRuntimeBehavior(SourceLoc
> const PartialDiagnostic &PD) {
> switch (ExprEvalContexts.back().Context) {
> case Unevaluated:
> + case UnevaluatedList:
> case UnevaluatedAbstract:
> case DiscardedStatement:
> // The argument will never be evaluated, so don't complain.
>
> Modified: cfe/trunk/lib/Sema/SemaExprMember.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprMember.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExprMember.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExprMember.cpp Fri Jan 6 18:48:55 2017
> @@ -134,6 +134,7 @@ static IMAKind ClassifyImplicitMemberAcc
> assert(!AbstractInstanceResult);
> switch (SemaRef.ExprEvalContexts.back().Context) {
> case Sema::Unevaluated:
> + case Sema::UnevaluatedList:
> if (isField && SemaRef.getLangOpts().CPlusPlus11)
> AbstractInstanceResult = IMA_Field_Uneval_Context;
> break;
>
> Modified: cfe/trunk/lib/Sema/SemaInit.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaInit.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Jan 6 18:48:55 2017
> @@ -6561,6 +6561,13 @@ InitializationSequence::Perform(Sema &S,
> break;
> }
>
> + // Promote from an unevaluated context to an unevaluated list context in
> + // C++11 list-initialization; we need to instantiate entities usable in
> + // constant expressions here in order to perform narrowing checks =(
> + EnterExpressionEvaluationContext Evaluated(
> + S, EnterExpressionEvaluationContext::InitList,
> + CurInit.get() && isa<InitListExpr>(CurInit.get()));
> +
> // C++ [class.abstract]p2:
> // no objects of an abstract class can be created except as subobjects
> // of a class derived from it
>
> Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaLambda.cpp Fri Jan 6 18:48:55 2017
> @@ -1565,6 +1565,7 @@ ExprResult Sema::BuildLambdaExpr(SourceL
> // A lambda-expression shall not appear in an unevaluated operand
> // (Clause 5).
> case Unevaluated:
> + case UnevaluatedList:
> case UnevaluatedAbstract:
> // C++1y [expr.const]p2:
> // A conditional-expression e is a core constant expression unless the
>
> Modified: cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp (original)
> +++ cfe/trunk/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp Fri Jan 6 18:48:55 2017
> @@ -139,11 +139,11 @@ namespace NonLocalLambdaInstantation {
> }
>
> template<typename T>
> - struct X2 { // expected-note{{in instantiation of default member initializer 'NonLocalLambdaInstantation::X2<int *>::x' requested here}}
> + struct X2 {
> int x = []{ return T(); }(); // expected-error{{cannot initialize a member subobject of type 'int' with an rvalue of type 'int *'}}
> };
>
> X2<int> x2i;
> X2<float> x2f;
> - X2<int*> x2ip; // expected-note{{implicit default constructor for 'NonLocalLambdaInstantation::X2<int *>' first required here}}
> + X2<int*> x2ip; // expected-note{{in instantiation of default member initializer 'NonLocalLambdaInstantation::X2<int *>::x'}}
> }
>
> Modified: cfe/trunk/test/CXX/temp/temp.param/p5.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p5.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/temp/temp.param/p5.cpp (original)
> +++ cfe/trunk/test/CXX/temp/temp.param/p5.cpp Fri Jan 6 18:48:55 2017
> @@ -1,13 +1,13 @@
> -// RUN: %clang_cc1 -verify %s -std=c++11
> +// RUN: %clang_cc1 -verify %s -std=c++14
>
> -template<const int I> struct S { // expected-note {{instantiation}}
> +template<const int I> struct S {
> decltype(I) n;
> int &&r = I; // expected-warning 2{{binding reference member 'r' to a temporary value}} expected-note 2{{declared here}}
> };
> -S<5> s;
> +S<5> s; // expected-note {{instantiation}}
>
> -template<typename T, T v> struct U { // expected-note {{instantiation}}
> +template<typename T, T v> struct U {
> decltype(v) n;
> int &&r = v; // expected-warning {{binding reference member 'r' to a temporary value}} expected-note {{declared here}}
> };
> -U<const int, 6> u;
> +U<const int, 6> u; // expected-note {{instantiation}}
>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Jan 6 18:48:55 2017
> @@ -1902,9 +1902,9 @@ namespace ZeroSizeTypes {
> namespace BadDefaultInit {
> template<int N> struct X { static const int n = N; };
>
> - struct A { // expected-error {{default member initializer for 'k' needed within definition of enclosing class}}
> + struct A {
> int k = // expected-note {{default member initializer declared here}}
> - X<A().k>::n; // expected-error {{not a constant expression}} expected-note {{implicit default constructor for 'BadDefaultInit::A' first required here}}
> + X<A().k>::n; // expected-error {{default member initializer for 'k' needed within definition of enclosing class}}
> };
>
> // FIXME: The "constexpr constructor must initialize all members" diagnostic
>
> Modified: cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp (original)
> +++ cfe/trunk/test/SemaCXX/implicit-exception-spec.cpp Fri Jan 6 18:48:55 2017
> @@ -16,34 +16,32 @@ namespace InClassInitializers {
> // Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
> // is false.
> bool ThrowSomething() noexcept(false);
> - struct ConstExpr { // expected-error {{default member initializer for 'b' needed}}
> - bool b = noexcept(ConstExpr()) && ThrowSomething(); // expected-note {{declared here}}
> - // expected-note at -1 {{implicit default constructor for 'InClassInitializers::ConstExpr' first required here}}
> + struct ConstExpr {
> + bool b = // expected-note {{declared here}}
> + noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{default member initializer for 'b' needed}}
> };
>
> // Much more obviously broken: we can't parse the initializer without already
> // knowing whether it produces a noexcept expression.
> - struct TemplateArg { // expected-error {{default member initializer for 'n' needed}}
> - int n = ExceptionIf<noexcept(TemplateArg())>::f(); // expected-note {{declared here}}
> - // expected-note at -1 {{implicit default constructor for 'InClassInitializers::TemplateArg' first required here}}
> + struct TemplateArg {
> + int n = // expected-note {{declared here}}
> + ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{default member initializer for 'n' needed}}
> };
>
> // And within a nested class.
> - struct Nested { // expected-note {{implicit default constructor for 'InClassInitializers::Nested::Inner' first required here}}
> - struct Inner { // expected-error {{default member initializer for 'n' needed}}
> + struct Nested {
> + struct Inner {
> int n = // expected-note {{declared here}}
> - ExceptionIf<noexcept(Nested())>::f(); // expected-note {{implicit default constructor for 'InClassInitializers::Nested' first required here}}
> - } inner;
> + ExceptionIf<noexcept(Nested())>::f();
> + } inner; // expected-error {{default member initializer for 'n' needed}}
> };
>
> - struct Nested2 { // expected-error {{implicit default constructor for 'InClassInitializers::Nested2' must explicitly initialize the member 'inner' which does not have a default constructor}}
> + struct Nested2 {
> struct Inner;
> - int n = Inner().n; // expected-note {{implicit default constructor for 'InClassInitializers::Nested2::Inner' first required here}}
> - struct Inner { // expected-error {{initializer for 'n' needed}} expected-note {{declared here}}
> - // expected-note at +1 {{declared here}}
> - int n = ExceptionIf<noexcept(Nested2())>::f();
> - // expected-note at -1 {{implicit default constructor for 'InClassInitializers::Nested2' first required here}}
> - } inner; // expected-note {{member is declared here}}
> + int n = Inner().n; // expected-error {{initializer for 'n' needed}}
> + struct Inner {
> + int n = ExceptionIf<noexcept(Nested2())>::f(); // expected-note {{declared here}}
> + } inner;
> };
> }
>
>
> Modified: cfe/trunk/test/SemaCXX/member-init.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-init.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/member-init.cpp (original)
> +++ cfe/trunk/test/SemaCXX/member-init.cpp Fri Jan 6 18:48:55 2017
> @@ -13,10 +13,10 @@ public:
>
> bool b();
> int k;
> -struct Recurse { // expected-error {{initializer for 'n' needed}}
> +struct Recurse {
> int &n = // expected-note {{declared here}}
> b() ?
> - Recurse().n : // expected-note {{implicit default constructor for 'Recurse' first required here}}
> + Recurse().n : // expected-error {{initializer for 'n' needed}}
> k;
> };
>
> @@ -128,21 +128,19 @@ A::A() {}
> namespace template_default_ctor {
> struct A {
> template <typename T>
> - struct B { // expected-error {{initializer for 'm1' needed}}
> + struct B {
> int m1 = 0; // expected-note {{declared here}}
> };
> - // expected-note at +1 {{implicit default constructor for 'template_default_ctor::A::B<int>' first required here}}
> - enum { NOE = noexcept(B<int>()) };
> + enum { NOE = noexcept(B<int>()) }; // expected-error {{initializer for 'm1' needed}}
> };
> }
>
> namespace default_ctor {
> struct A {
> - struct B { // expected-error {{initializer for 'm1' needed}}
> + struct B {
> int m1 = 0; // expected-note {{declared here}}
> };
> - // expected-note at +1 {{implicit default constructor for 'default_ctor::A::B' first required here}}
> - enum { NOE = noexcept(B()) };
> + enum { NOE = noexcept(B()) }; // expected-error {{initializer for 'm1' needed}}
> };
> }
>
> @@ -150,19 +148,17 @@ namespace member_template {
> struct A {
> template <typename T>
> struct B {
> - struct C { // expected-error {{initializer for 'm1' needed}}
> + struct C {
> int m1 = 0; // expected-note {{declared here}}
> };
> template <typename U>
> - struct D { // expected-error {{initializer for 'm1' needed}}
> + struct D {
> int m1 = 0; // expected-note {{declared here}}
> };
> };
> enum {
> - // expected-note at +1 {{implicit default constructor for 'member_template::A::B<int>::C' first required here}}
> - NOE1 = noexcept(B<int>::C()),
> - // expected-note at +1 {{implicit default constructor for 'member_template::A::B<int>::D<int>' first required here}}
> - NOE2 = noexcept(B<int>::D<int>())
> + NOE1 = noexcept(B<int>::C()), // expected-error {{initializer for 'm1' needed}}
> + NOE2 = noexcept(B<int>::D<int>()) // expected-error {{initializer for 'm1' needed}}
> };
> };
> }
>
> Modified: cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp (original)
> +++ cfe/trunk/test/SemaTemplate/constexpr-instantiate.cpp Fri Jan 6 18:48:55 2017
> @@ -77,20 +77,19 @@ namespace Reference {
> }
>
> namespace Unevaluated {
> - // We follow g++ in treating any reference to a constexpr function template
> - // specialization as requiring an instantiation, even if it occurs in an
> - // unevaluated context.
> + // We follow the current proposed resolution of core issue 1581: a constexpr
> + // function template specialization requires a definition if:
> + // * it is odr-used, or would be odr-used except that it appears within the
> + // definition of a template, or
> + // * it is used within a braced-init-list, where it may be necessary for
> + // detecting narrowing conversions.
> //
> - // We go slightly further than g++, and also trigger the implicit definition
> - // of a defaulted special member in the same circumstances. This seems scary,
> - // since a lot of classes have constexpr special members in C++11, but the
> - // only observable impact should be the implicit instantiation of constexpr
> - // special member templates (defaulted special members should only be
> - // generated if they are well-formed, and non-constexpr special members in a
> - // base or member cause the class's special member to not be constexpr).
> + // We apply this both for instantiating constexpr function template
> + // specializations and for implicitly defining defaulted constexpr special
> + // member functions.
> //
> - // FIXME: None of this is required by the C++ standard. The rules in this
> - // area are poorly specified, so this is subject to change.
> + // FIXME: None of this is required by the C++ standard yet. The rules in this
> + // area are subject to change.
> namespace NotConstexpr {
> template<typename T> struct S {
> S() : n(0) {}
> @@ -98,16 +97,35 @@ namespace Unevaluated {
> int n;
> };
> struct U : S<int> {};
> - decltype(U(U())) u; // ok, don't instantiate S<int>::S() because it wasn't declared constexpr
> + decltype(U(U())) u;
> }
> namespace Constexpr {
> template<typename T> struct S {
> constexpr S() : n(0) {}
> - constexpr S(const S&) : n(T::error) {} // expected-error {{has no members}}
> + constexpr S(const S&) : n(T::error) {}
> int n;
> };
> - struct U : S<int> {}; // expected-note {{instantiation}}
> - decltype(U(U())) u; // expected-note {{here}}
> + struct U : S<int> {};
> + decltype(U(U())) u;
> + }
> + namespace ConstexprList {
> + template<int N> struct S {
> + constexpr S() : n(0) {
> + static_assert(N >= 0, "");
> + }
> + constexpr operator int() const { return 0; }
> + int n;
> + };
> + struct U : S<0> {};
> + // ok, trigger instantiation within a list
> + decltype(char{U()}) t0;
> + decltype(new char{S<1>()}) t1; // expected-warning {{side effects}}
> + decltype((char){S<2>()}) t2;
> + decltype(+(char[1]){{S<3>()}}) t3;
> + // do not trigger instantiation outside a list
> + decltype(char(S<-1>())) u1;
> + decltype(new char(S<-2>())) u2; // expected-warning {{side effects}}
> + decltype((char)(S<-3>())) u3;
> }
>
> namespace PR11851_Comment0 {
> @@ -190,6 +208,32 @@ namespace Unevaluated {
> constexpr duration max = duration();
> }
> }
> +
> + // For variables, we instantiate when they are used in a context in which
> + // evaluation could be required (odr-used, used in a template whose
> + // instantiations would odr-use, or used in list initialization), if they
> + // can be used as a constant (const integral or constexpr).
> + namespace Variables {
> + template<int N> struct A {
> + static const int k;
> + static int n;
> + };
> + template<const int *N> struct B {};
> + template<int N> constexpr int A<N>::k = *(int[N]){N}; // expected-error 1+{{negative}}
> + template<int N> int A<N>::n = *(int[N]){0};
> +
> + template <typename> void f() {
> + (void)A<-1>::n; // ok
> + (void)A<-1>::k; // expected-note {{instantiation of }}
> + B<&A<-2>::n> b1; // ok
> + B<&A<-2>::k> b2; // expected-note {{instantiation of }}
> + };
> +
> + decltype(A<-3>::k) d1 = 0; // ok
> + decltype(char{A<-4>::k}) d2 = 0; // expected-note {{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
> + decltype(char{A<1>::k}) d3 = 0; // ok
> + decltype(char{A<1 + (unsigned char)-1>::k}) d4 = 0; // expected-error {{narrow}} expected-note {{cast}}
> + }
> }
>
> namespace NoInstantiationWhenSelectingOverload {
> @@ -201,10 +245,10 @@ namespace NoInstantiationWhenSelectingOv
> int n;
> };
>
> - int f(S);
> - int f(int);
> + constexpr int f(S) { return 0; }
> + constexpr int f(int) { return 0; }
>
> void g() { f(0); }
> - void h() { (void)sizeof(f(0)); }
> - void i() { (void)sizeof(f("oops")); } // expected-note {{instantiation of}}
> + void h() { (void)sizeof(char{f(0)}); }
> + void i() { (void)sizeof(char{f("oops")}); } // expected-note {{instantiation of}}
> }
>
> Modified: cfe/trunk/test/SemaTemplate/default-arguments-cxx0x.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-arguments-cxx0x.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/default-arguments-cxx0x.cpp (original)
> +++ cfe/trunk/test/SemaTemplate/default-arguments-cxx0x.cpp Fri Jan 6 18:48:55 2017
> @@ -50,6 +50,8 @@ namespace PR16975 {
> bar(T);
> };
>
> + bar<> foo{0};
> +
> struct baz : public bar<> {
> using bar::bar;
> };
>
> Modified: cfe/trunk/test/SemaTemplate/instantiate-init.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-init.cpp?rev=291318&r1=291317&r2=291318&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/instantiate-init.cpp (original)
> +++ cfe/trunk/test/SemaTemplate/instantiate-init.cpp Fri Jan 6 18:48:55 2017
> @@ -115,9 +115,8 @@ namespace PR13064 {
> struct A { explicit A(int); }; // expected-note{{here}}
> template<typename T> struct B { T a { 0 }; };
> B<A> b;
> - // expected-note at +1 {{in instantiation of default member initializer}}
> template<typename T> struct C { T a = { 0 }; }; // expected-error{{explicit}}
> - C<A> c; // expected-note{{here}}
> + C<A> c; // expected-note {{in instantiation of default member initializer}}
> }
>
> namespace PR16903 {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list