[Sema] Fix handling of enumerators used as default arguments of lambda

expressions in a function or class template.

This patch makes the following changes:

- Create a DependentScopeDeclRefExpr for the default argument instead of
  a CXXDependentScopeMemberExpr.
- Pass CombineWithOuterScope=true so that the outer scope in which the
  enum is declared is searched for the instantiation of the enum. 

This is the first part of https://reviews.llvm.org/D23096. Fixes PR28795

rdar://problem/27535319

llvm-svn: 289914
This commit is contained in:
Akira Hatanaka 2016-12-16 03:19:41 +00:00
parent 3826727453
commit d644e021b5
3 changed files with 42 additions and 2 deletions

View File

@ -429,7 +429,12 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
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<EnumType>(NNS->getAsType());
if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum &&
isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->isInstance()) {
QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);

View File

@ -1687,7 +1687,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
// 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.

View File

@ -0,0 +1,35 @@
// RUN: %clang_cc1 -std=c++14 -emit-llvm -disable-llvm-optzns -verify %s
// expected-no-diagnostics
namespace PR28795 {
template<typename T>
void func() {
enum class foo { a, b };
auto bar = [](foo f = foo::a) { return f; };
bar();
}
void foo() {
func<int>();
}
}
// Template struct case:
template <class T> struct class2 {
void bar() {
enum class foo { a, b };
[](foo f = foo::a) { return f; }();
}
};
template struct class2<int>;
template<typename T>
void f1() {
enum class foo { a, b };
struct S {
int g1(foo n = foo::a);
};
}
template void f1<int>();