Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -6616,6 +6616,8 @@ bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); + ArrayRef varTemplateArguments() const; + /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { /// \brief The kind of template instantiation we are performing @@ -6835,9 +6837,10 @@ /// \brief Note that we are instantiating a class template, /// function template, variable template, alias template, /// or a member thereof. - InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - Decl *Entity, - SourceRange InstantiationRange = SourceRange()); + InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, + SourceRange InstantiationRange = SourceRange(), + ArrayRef TemplateArgs = ArrayRef()); struct ExceptionSpecification {}; /// \brief Note that we are instantiating an exception specification Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -429,7 +429,12 @@ bool MightBeCxx11UnevalField = getLangOpts().CPlusPlus11 && isUnevaluatedContext(); - if (!MightBeCxx11UnevalField && !isAddressOfOperand && + // Check if the nested name specifier is an enum type. + bool IsEnum = false; + if (NestedNameSpecifier *NNS = SS.getScopeRep()) + IsEnum = dyn_cast_or_null(NNS->getAsType()); + + if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum && isa(DC) && cast(DC)->isInstance()) { QualType ThisType = cast(DC)->getThisType(Context); Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -57,9 +57,16 @@ // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; + ArrayRef VarTemplateArgs = varTemplateArguments(); + + if (!VarTemplateArgs.empty()) { + Result.addOuterTemplateArguments(VarTemplateArgs); + return Result; + } + if (Innermost) Result.addOuterTemplateArguments(Innermost); - + DeclContext *Ctx = dyn_cast(D); if (!Ctx) { Ctx = D->getDeclContext(); @@ -183,6 +190,19 @@ return Result; } +ArrayRef Sema::varTemplateArguments() const { + if (ActiveTemplateInstantiations.empty()) + return ArrayRef(); + + const auto &Inst = ActiveTemplateInstantiations.back(); + + if (const auto *VD = dyn_cast_or_null(Inst.Entity)) + if (VD->getDescribedVarTemplate() || VD->getTemplateSpecializationKind()) + return Inst.template_arguments(); + + return ArrayRef(); +} + bool Sema::ActiveTemplateInstantiation::isInstantiationRecord() const { switch (Kind) { case TemplateInstantiation: @@ -234,10 +254,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, - SourceRange InstantiationRange) + SourceRange InstantiationRange, ArrayRef TemplateArgs) : InstantiatingTemplate(SemaRef, ActiveTemplateInstantiation::TemplateInstantiation, - PointOfInstantiation, InstantiationRange, Entity) {} + PointOfInstantiation, InstantiationRange, Entity, + nullptr, TemplateArgs) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity, @@ -1670,7 +1691,7 @@ // Instantiate default arguments for methods of local classes (DR1484) // and non-defining declarations. Sema::ContextRAII SavedContext(*this, OwningFunc); - LocalInstantiationScope Local(*this); + LocalInstantiationScope Local(*this, true); ExprResult NewArg = SubstExpr(Arg, TemplateArgs); if (NewArg.isUsable()) { // It would be nice if we still had this. Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3728,7 +3728,8 @@ if (FromVar->isInvalidDecl()) return nullptr; - InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar); + InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar, + SourceRange(), TemplateArgList.asArray()); if (Inst.isInvalid()) return nullptr; @@ -4022,7 +4023,8 @@ !Var->hasInit()) { // FIXME: Factor out the duplicated instantiation context setup/tear down // code here. - InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); + InstantiatingTemplate Inst(*this, PointOfInstantiation, Var, + SourceRange(), TemplateArgs.getInnermost()); if (Inst.isInvalid()) return; PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), Index: test/SemaCXX/vartemplate-lambda.cpp =================================================================== --- test/SemaCXX/vartemplate-lambda.cpp +++ test/SemaCXX/vartemplate-lambda.cpp @@ -1,15 +1,22 @@ // RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s -// expected-no-diagnostics template auto fn0 = [] {}; template void foo0() { fn0(); } template auto fn1 = [](auto a) { return a + T(1); }; +template auto v1 = [](int a = T(1)) { return a; }(); + +struct S { + template + static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't' must be initialized by a constant expression}} expected-error{{a lambda expression may not appear inside of a constant expression}} expected-note{{cannot be used in a constant expression}} +}; template int foo2() { X a = 0x61; fn1(a); + (void)v1; + (void)S::t; // expected-note{{in instantiation of static data member 'S::t' requested here}} return 0; } Index: test/SemaTemplate/default-expr-arguments-3.cpp =================================================================== --- /dev/null +++ test/SemaTemplate/default-expr-arguments-3.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -std=c++14 -ast-dump %s 2>&1 | FileCheck %s + +namespace PR28795 { + // CHECK: FunctionDecl{{.*}}func 'void (void)' + // CHECK: LambdaExpr + // CHECK: CXXMethodDecl{{.*}}operator() 'enum foo (enum foo) const' inline + // CHECK: ParmVarDecl{{.*}}f 'enum foo' cinit + // CHECK: DeclRefExpr{{.*}}'enum foo' EnumConstant{{.*}}'a' 'enum foo' + + template + void func() { + enum class foo { a, b }; + auto bar = [](foo f = foo::a) { return f; }; + bar(); + } + + void foo() { + func(); + } +} + +// Template struct case: + +// CHECK: ClassTemplateSpecializationDecl{{.*}}struct class2 definition +// CHECK: LambdaExpr +// CHECK: CXXMethodDecl{{.*}}used operator() 'enum foo (enum foo) const' inline +// CHECK: ParmVarDecl{{.*}}f 'enum foo' cinit +// CHECK: DeclRefExpr{{.*}}'enum foo' EnumConstant{{.*}}'a' 'enum foo' + +template struct class2 { + void bar() { + enum class foo { a, b }; + [](foo f = foo::a) { return f; }(); + } +}; + +template struct class2; + +// CHECK: FunctionDecl{{.*}}f1 'void (void)' +// CHECK: CXXMethodDecl{{.*}}g1 'int (enum foo)' +// CHECK: ParmVarDecl{{.*}}n 'enum foo' cinit +// CHECK: DeclRefExpr{{.*}}'enum foo' EnumConstant{{.*}}'a' 'enum foo' + +template +void f1() { + enum class foo { a, b }; + struct S { + int g1(foo n = foo::a); + }; +} + +template void f1();