]> granicus.if.org Git - clang/commitdiff
Relax the construction of a definition for implicit, trivial default
authorChandler Carruth <chandlerc@gmail.com>
Mon, 23 Aug 2010 07:55:51 +0000 (07:55 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Mon, 23 Aug 2010 07:55:51 +0000 (07:55 +0000)
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

lib/Sema/SemaExpr.cpp
lib/Sema/SemaInit.cpp
test/SemaCXX/default-constructor-initializers.cpp

index 36a1e4e2778f58c378bfe249913802d9ed11192b..6a62a1a12dfdc466b3e2142384692c5ce64bf0d5 100644 (file)
@@ -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))
index 6d7d3a9b107c9422f0c05fbe8e673a330b8153f7..7fc23d610ecd8faa50e29ad4464aadf535ebf76c 100644 (file)
@@ -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 ||
index 757332df0b058056bcf663c506faa49422b50cd9..9da85567beda64f9ead56d1ea8ad858299493b06 100644 (file)
@@ -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 } };
+}