aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2010-08-23 07:55:51 +0000
committerChandler Carruth <chandlerc@gmail.com>2010-08-23 07:55:51 +0000
commit4e6fbce4277fbc7c574fb2393c7dfe06f014c21a (patch)
treee7e3bb89dec1144843980740fb7feca37e3f0d3c
parent2b5289b6fd7e3d9899868410a498c081c9595662 (diff)
Relax the construction of a definition for implicit, trivial default
constructors. We perform semantic checking when creating the definition, and this isn't needed in certain contexts (value initialization) but is in others (default initialization). This fixes PR7948. We add explicit code to the default initialization path to ensure the definition is both present and valid. Doug, please review. I think this follows your latest suggestion, and it ended up remarkably cleaner than I anticipated. Also let me know if similar logic should be followed for destructors and copy-constructors. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111802 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaExpr.cpp6
-rw-r--r--lib/Sema/SemaInit.cpp19
-rw-r--r--test/SemaCXX/default-constructor-initializers.cpp8
3 files changed, 26 insertions, 7 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 36a1e4e277..6a62a1a12d 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7654,8 +7654,10 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
unsigned TypeQuals;
if (Constructor->isImplicit() && Constructor->isDefaultConstructor()) {
- if (!Constructor->isUsed(false))
- DefineImplicitDefaultConstructor(Loc, Constructor);
+ if (Constructor->getParent()->hasTrivialConstructor())
+ return;
+ if (!Constructor->isUsed(false))
+ DefineImplicitDefaultConstructor(Loc, Constructor);
} else if (Constructor->isImplicit() &&
Constructor->isCopyConstructor(TypeQuals)) {
if (!Constructor->isUsed(false))
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 6d7d3a9b10..7fc23d610e 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -2862,8 +2862,8 @@ static void TryDefaultInitialization(Sema &S,
// constructor for T is called (and the initialization is ill-formed if
// T has no accessible default constructor);
if (DestType->isRecordType() && S.getLangOptions().CPlusPlus) {
- return TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType,
- Sequence);
+ TryConstructorInitialization(S, Entity, Kind, 0, 0, DestType, Sequence);
+ return;
}
// - otherwise, no initialization is performed.
@@ -3838,14 +3838,25 @@ InitializationSequence::Perform(Sema &S,
SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid())
? Kind.getEqualLoc()
: Kind.getLocation();
-
+
+ if (Kind.getKind() == InitializationKind::IK_Default) {
+ // Force even a trivial, implicit default constructor to be
+ // semantically checked. We do this explicitly because we don't build
+ // the definition for completely trivial constructors.
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+ assert(ClassDecl && "No parent class for constructor.");
+ if (Constructor->isImplicit() && Constructor->isDefaultConstructor() &&
+ ClassDecl->hasTrivialConstructor() && !Constructor->isUsed(false))
+ S.DefineImplicitDefaultConstructor(Loc, Constructor);
+ }
+
// Determine the arguments required to actually perform the constructor
// call.
if (S.CompleteConstructorCall(Constructor, move(Args),
Loc, ConstructorArgs))
return S.ExprError();
- // Build the expression that constructs a temporary.
+
if (Entity.getKind() == InitializedEntity::EK_Temporary &&
NumArgs != 1 && // FIXME: Hack to work around cast weirdness
(Kind.getKind() == InitializationKind::IK_Direct ||
diff --git a/test/SemaCXX/default-constructor-initializers.cpp b/test/SemaCXX/default-constructor-initializers.cpp
index 757332df0b..9da85567be 100644
--- a/test/SemaCXX/default-constructor-initializers.cpp
+++ b/test/SemaCXX/default-constructor-initializers.cpp
@@ -43,7 +43,6 @@ Y4 y4;
// More tests
-
struct Z1 { // expected-error {{must explicitly initialize the reference member 'z'}} \
// expected-error {{must explicitly initialize the const member 'c1'}}
int& z; // expected-note {{declared here}}
@@ -51,5 +50,12 @@ struct Z1 { // expected-error {{must explicitly initialize the reference member
volatile int v1;
};
+// Test default initialization which *requires* a constructor call for non-POD.
Z1 z1; // expected-note {{first required here}}
+// Ensure that value initialization doesn't use trivial implicit constructors.
+namespace PR7948 {
+ // Note that this is also non-POD to ensure we don't just special case PODs.
+ struct S { const int x; ~S(); };
+ const S arr[2] = { { 42 } };
+}