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@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@-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@-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@+1 {{declared here}} > - int n = ExceptionIf<noexcept(Nested2())>::f(); > - // expected-note@-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@+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@+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@+1 {{implicit default constructor for > 'member_template::A::B<int>::C' first required here}} > - NOE1 = noexcept(B<int>::C()), > - // expected-note@+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@+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@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits