void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
CXXConstructorDecl *CD);
- void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx, Expr *DAE);
-
- Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx);
-
void addTypedefNameForUnnamedTagDecl(TagDecl *TD, TypedefNameDecl *TND);
TypedefNameDecl *getTypedefNameForUnnamedTagDecl(const TagDecl *TD);
ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field);
+
+ /// Instantiate or parse a C++ default argument expression as necessary.
+ /// Return true on error.
+ bool CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
+ ParmVarDecl *Param);
+
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating
/// the default expr if needed.
ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc,
cast<CXXConstructorDecl>(CD->getFirstDecl()));
}
-void ASTContext::addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx, Expr *DAE) {
- ABI->addDefaultArgExprForConstructor(
- cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx, DAE);
-}
-
-Expr *ASTContext::getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx) {
- return ABI->getDefaultArgExprForConstructor(
- cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx);
-}
-
void ASTContext::addTypedefNameForUnnamedTagDecl(TagDecl *TD,
TypedefNameDecl *DD) {
return ABI->addTypedefNameForUnnamedTagDecl(TD, DD);
virtual const CXXConstructorDecl *
getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0;
- virtual void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx, Expr *DAE) = 0;
-
- virtual Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx) = 0;
-
virtual void addTypedefNameForUnnamedTagDecl(TagDecl *TD,
TypedefNameDecl *DD) = 0;
void addCopyConstructorForExceptionObject(CXXRecordDecl *RD,
CXXConstructorDecl *CD) override {}
- void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx, Expr *DAE) override {}
-
- Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx) override {
- return nullptr;
- }
-
void addTypedefNameForUnnamedTagDecl(TagDecl *TD,
TypedefNameDecl *DD) override {}
class MicrosoftCXXABI : public CXXABI {
ASTContext &Context;
llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor;
- llvm::SmallDenseMap<std::pair<const CXXConstructorDecl *, unsigned>, Expr *>
- CtorToDefaultArgExpr;
llvm::SmallDenseMap<TagDecl *, DeclaratorDecl *>
UnnamedTagDeclToDeclaratorDecl;
llvm_unreachable("unapplicable to the MS ABI");
}
- void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx, Expr *DAE) override {
- CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)] = DAE;
- }
-
- Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD,
- unsigned ParmIdx) override {
- return CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)];
- }
-
const CXXConstructorDecl *
getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override {
return RecordToCopyCtor[RD];
Args.add(RValue::get(SrcVal), SrcParam.getType());
// Add the rest of the default arguments.
- std::vector<Stmt *> ArgVec;
- for (unsigned I = IsCopy ? 1 : 0, E = CD->getNumParams(); I != E; ++I) {
- Stmt *DefaultArg = getContext().getDefaultArgExprForConstructor(CD, I);
- assert(DefaultArg && "sema forgot to instantiate default args");
- ArgVec.push_back(DefaultArg);
+ SmallVector<const Stmt *, 4> ArgVec;
+ ArrayRef<ParmVarDecl *> params = CD->parameters().drop_front(IsCopy ? 1 : 0);
+ for (const ParmVarDecl *PD : params) {
+ assert(PD->hasDefaultArg() && "ctor closure lacks default args");
+ ArgVec.push_back(PD->getDefaultArg());
}
CodeGenFunction::RunCleanupsScope Cleanups(CGF);
}
}
-static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
+static void checkDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) {
// Don't do anything for template patterns.
if (Class->getDescribedClassTemplate())
return;
if (!CD) {
// Recurse on nested classes.
if (auto *NestedRD = dyn_cast<CXXRecordDecl>(Member))
- getDefaultArgExprsForConstructors(S, NestedRD);
+ checkDefaultArgExprsForConstructors(S, NestedRD);
continue;
} else if (!CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>()) {
continue;
LastExportedDefaultCtor = CD;
for (unsigned I = 0; I != NumParams; ++I) {
- // Skip any default arguments that we've already instantiated.
- if (S.Context.getDefaultArgExprForConstructor(CD, I))
- continue;
-
- Expr *DefaultArg = S.BuildCXXDefaultArgExpr(Class->getLocation(), CD,
- CD->getParamDecl(I)).get();
+ (void)S.CheckCXXDefaultArgExpr(Class->getLocation(), CD,
+ CD->getParamDecl(I));
S.DiscardCleanupsInEvaluationContext();
- S.Context.addDefaultArgExprForConstructor(CD, I, DefaultArg);
}
}
}
// have default arguments or don't use the standard calling convention are
// wrapped with a thunk called the default constructor closure.
if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft())
- getDefaultArgExprsForConstructors(*this, RD);
+ checkDefaultArgExprsForConstructors(*this, RD);
referenceDLLExportedClassMethods();
}
ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc);
}
-ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
- FunctionDecl *FD,
- ParmVarDecl *Param) {
+bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
+ ParmVarDecl *Param) {
if (Param->hasUnparsedDefaultArg()) {
Diag(CallLoc,
diag::err_use_of_default_argument_to_function_declared_later) <<
FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName();
Diag(UnparsedDefaultArgLocs[Param],
diag::note_default_argument_declared_here);
- return ExprError();
+ return true;
}
if (Param->hasUninstantiatedDefaultArg()) {
InstantiatingTemplate Inst(*this, CallLoc, Param,
MutiLevelArgList.getInnermost());
if (Inst.isInvalid())
- return ExprError();
+ return true;
if (Inst.isAlreadyInstantiating()) {
Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD;
Param->setInvalidDecl();
- return ExprError();
+ return true;
}
ExprResult Result;
/*DirectInit*/false);
}
if (Result.isInvalid())
- return ExprError();
+ return true;
// Check the expression as an initializer for the parameter.
InitializedEntity Entity
InitializationSequence InitSeq(*this, Entity, Kind, ResultE);
Result = InitSeq.Perform(*this, Entity, Kind, ResultE);
if (Result.isInvalid())
- return ExprError();
+ return true;
Result = ActOnFinishFullExpr(Result.getAs<Expr>(),
Param->getOuterLocStart());
if (Result.isInvalid())
- return ExprError();
+ return true;
// Remember the instantiated default argument.
Param->setDefaultArg(Result.getAs<Expr>());
if (!Param->hasInit()) {
Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD;
Param->setInvalidDecl();
- return ExprError();
+ return true;
}
// If the default expression creates temporaries, we need to
// as being "referenced".
MarkDeclarationsReferencedInExpr(Param->getDefaultArg(),
/*SkipLocalVariables=*/true);
- return CXXDefaultArgExpr::Create(Context, CallLoc, Param);
+ return false;
}
+ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
+ FunctionDecl *FD, ParmVarDecl *Param) {
+ if (CheckCXXDefaultArgExpr(CallLoc, FD, Param))
+ return ExprError();
+ return CXXDefaultArgExpr::Create(Context, CallLoc, Param);
+}
Sema::VariadicCallType
Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto,
// We don't keep the instantiated default argument expressions around so
// we must rebuild them here.
for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) {
- // Skip any default arguments that we've already instantiated.
- if (Context.getDefaultArgExprForConstructor(CD, I))
- continue;
-
- Expr *DefaultArg =
- BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get();
- Context.addDefaultArgExprForConstructor(CD, I, DefaultArg);
+ if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)))
+ return true;
}
}
}
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fexceptions -fcxx-exceptions -fms-extensions -verify %s -std=c++11
+
+// The MS ABI has a few ways to generate constructor closures, which require
+// instantiating and checking the semantics of default arguments. Make sure we
+// do that right.
+
+// FIXME: Don't diagnose this issue twice.
+template <typename T>
+struct DependentDefaultCtorArg { // expected-note {{in instantiation of default function argument}}
+ // expected-error@+1 2 {{type 'int' cannot be used prior to '::' because it has no members}}
+ DependentDefaultCtorArg(int n = T::error);
+};
+struct
+__declspec(dllexport) // expected-note {{due to 'ExportDefaultCtorClosure' being dllexported}}
+ExportDefaultCtorClosure // expected-note {{implicit default constructor for 'ExportDefaultCtorClosure' first required here}}
+: DependentDefaultCtorArg<int> // expected-note {{in instantiation of template class}}
+{};
+
+template <typename T>
+struct DependentDefaultCopyArg {
+ DependentDefaultCopyArg() {}
+ // expected-error@+1 {{type 'int' cannot be used prior to '::' because it has no members}}
+ DependentDefaultCopyArg(const DependentDefaultCopyArg &o, int n = T::member) {}
+};
+
+struct HasMember {
+ enum { member = 0 };
+};
+void UseDependentArg() { throw DependentDefaultCopyArg<HasMember>(); }
+
+void ErrorInDependentArg() {
+ throw DependentDefaultCopyArg<int>(); // expected-note {{required here}}
+}
+
+struct HasCleanup {
+ ~HasCleanup();
+};
+
+struct Default {
+ Default(const Default &o, int d = (HasCleanup(), 42));
+};
+
+void f(const Default &d) {
+ throw d;
+}