[clang] eb10b06 - [clang] Pass the NamedDecl* instead of the DeclarationName into many diagnostics.

Bruno Ricci via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 28 02:36:37 PDT 2020


Author: Bruno Ricci
Date: 2020-07-28T10:30:35+01:00
New Revision: eb10b065f2a870b425dcc2040b9955e0eee464b4

URL: https://github.com/llvm/llvm-project/commit/eb10b065f2a870b425dcc2040b9955e0eee464b4
DIFF: https://github.com/llvm/llvm-project/commit/eb10b065f2a870b425dcc2040b9955e0eee464b4.diff

LOG: [clang] Pass the NamedDecl* instead of the DeclarationName into many diagnostics.

Background:
-----------
There are two related argument types which can be sent into a diagnostic to
display the name of an entity: DeclarationName (ak_declarationname) or
NamedDecl* (ak_nameddecl) (there is also ak_identifierinfo for
IdentifierInfo*, but we are not concerned with it here).

A DeclarationName in a diagnostic will just be streamed to the output,
which will directly result in a call to DeclarationName::print.

A NamedDecl* in a diagnostic will also ultimately result in a call to
DeclarationName::print, but with two customisation points along the way:

The first customisation point is NamedDecl::getNameForDiagnostic which is
overloaded by FunctionDecl, ClassTemplateSpecializationDecl and
VarTemplateSpecializationDecl to print the template arguments, if any.

The second customisation point is NamedDecl::printName. By default it just
streams the stored DeclarationName into the output but it can be customised
to provide a user-friendly name for an entity. It is currently overloaded by
DecompositionDecl and MSGuidDecl.

What this patch does:
---------------------
For many diagnostics a DeclarationName is used instead of the NamedDecl*.
This bypasses the two customisation points mentioned above. This patches fix
this for diagnostics in Sema.cpp, SemaCast.cpp, SemaChecking.cpp, SemaDecl.cpp,
SemaDeclAttr.cpp, SemaDecl.cpp, SemaOverload.cpp and SemaStmt.cpp.

I have only modified diagnostics where I could construct a test-case which
demonstrates that the change is appropriate (either with this patch or the next
one).

Reviewed By: erichkeane, aaron.ballman

Differential Revision: https://reviews.llvm.org/D84656

Added: 
    

Modified: 
    clang/lib/Sema/Sema.cpp
    clang/lib/Sema/SemaCast.cpp
    clang/lib/Sema/SemaChecking.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/SemaStmt.cpp
    clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
    clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp
    clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
    clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
    clang/test/Modules/module-private.cpp
    clang/test/SemaCXX/array-bounds.cpp
    clang/test/SemaCXX/attr-unused.cpp
    clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
    clang/test/SemaCXX/default2.cpp
    clang/test/SemaCXX/incomplete-call.cpp
    clang/test/SemaCXX/references.cpp
    clang/test/SemaCXX/return-void.cpp
    clang/test/SemaCXX/warn-func-not-needed.cpp
    clang/test/SemaCXX/warn-large-by-value-copy.cpp
    clang/test/SemaCXX/warn-member-not-needed.cpp
    clang/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
    clang/test/SemaCXX/warn-pure-virtual-kext.cpp
    clang/test/SemaCXX/warn-unused-filescoped.cpp
    clang/test/SemaCXX/warn-variable-not-needed.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 9c8f3fdcda4a..7415d0d0766b 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1197,7 +1197,7 @@ void Sema::ActOnEndOfTranslationUnit() {
         if (DiagD->isReferenced()) {
           if (isa<CXXMethodDecl>(DiagD))
             Diag(DiagD->getLocation(), diag::warn_unneeded_member_function)
-                  << DiagD->getDeclName();
+                << DiagD;
           else {
             if (FD->getStorageClass() == SC_Static &&
                 !FD->isInlineSpecified() &&
@@ -1205,20 +1205,20 @@ void Sema::ActOnEndOfTranslationUnit() {
                    SourceMgr.getExpansionLoc(FD->getLocation())))
               Diag(DiagD->getLocation(),
                    diag::warn_unneeded_static_internal_decl)
-                  << DiagD->getDeclName();
+                  << DiagD;
             else
               Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
-                   << /*function*/0 << DiagD->getDeclName();
+                  << /*function*/ 0 << DiagD;
           }
         } else {
           if (FD->getDescribedFunctionTemplate())
             Diag(DiagD->getLocation(), diag::warn_unused_template)
-              << /*function*/0 << DiagD->getDeclName();
+                << /*function*/ 0 << DiagD;
           else
-            Diag(DiagD->getLocation(),
-                 isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
+            Diag(DiagD->getLocation(), isa<CXXMethodDecl>(DiagD)
+                                           ? diag::warn_unused_member_function
                                            : diag::warn_unused_function)
-              << DiagD->getDeclName();
+                << DiagD;
         }
       } else {
         const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition();
@@ -1226,20 +1226,19 @@ void Sema::ActOnEndOfTranslationUnit() {
           DiagD = cast<VarDecl>(*I);
         if (DiagD->isReferenced()) {
           Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
-                << /*variable*/1 << DiagD->getDeclName();
+              << /*variable*/ 1 << DiagD;
         } else if (DiagD->getType().isConstQualified()) {
           const SourceManager &SM = SourceMgr;
           if (SM.getMainFileID() != SM.getFileID(DiagD->getLocation()) ||
               !PP.getLangOpts().IsHeaderFile)
             Diag(DiagD->getLocation(), diag::warn_unused_const_variable)
-                << DiagD->getDeclName();
+                << DiagD;
         } else {
           if (DiagD->getDescribedVarTemplate())
             Diag(DiagD->getLocation(), diag::warn_unused_template)
-              << /*variable*/1 << DiagD->getDeclName();
+                << /*variable*/ 1 << DiagD;
           else
-            Diag(DiagD->getLocation(), diag::warn_unused_variable)
-              << DiagD->getDeclName();
+            Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD;
         }
       }
     }

diff  --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
index 2efe26052c78..58cf3a1be730 100644
--- a/clang/lib/Sema/SemaCast.cpp
+++ b/clang/lib/Sema/SemaCast.cpp
@@ -510,12 +510,10 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType,
     if (RecFrom && RecTo) {
       auto DeclFrom = RecFrom->getAsCXXRecordDecl();
       if (!DeclFrom->isCompleteDefinition())
-        S.Diag(DeclFrom->getLocation(), diag::note_type_incomplete)
-          << DeclFrom->getDeclName();
+        S.Diag(DeclFrom->getLocation(), diag::note_type_incomplete) << DeclFrom;
       auto DeclTo = RecTo->getAsCXXRecordDecl();
       if (!DeclTo->isCompleteDefinition())
-        S.Diag(DeclTo->getLocation(), diag::note_type_incomplete)
-          << DeclTo->getDeclName();
+        S.Diag(DeclTo->getLocation(), diag::note_type_incomplete) << DeclTo;
     }
   }
 }

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f445272b020b..77d5f3ff816e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -13962,8 +13962,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
 
   if (ND)
     DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr,
-                        PDiag(diag::note_array_declared_here)
-                            << ND->getDeclName());
+                        PDiag(diag::note_array_declared_here) << ND);
 }
 
 void Sema::CheckArrayAccess(const Expr *expr) {

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 869e4de02cc4..ddbf086ea638 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -1926,7 +1926,7 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
   else
     Diagnose = L->getStmt() == nullptr;
   if (Diagnose)
-    S.Diag(L->getLocation(), diag::err_undeclared_label_use) <<L->getDeclName();
+    S.Diag(L->getLocation(), diag::err_undeclared_label_use) << L;
 }
 
 void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
@@ -7194,9 +7194,10 @@ NamedDecl *Sema::ActOnVariableDeclarator(
         << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
     else if (NewVD->hasLocalStorage())
       Diag(NewVD->getLocation(), diag::err_module_private_local)
-        << 0 << NewVD->getDeclName()
-        << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
-        << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
+          << 0 << NewVD
+          << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
+          << FixItHint::CreateRemoval(
+                 D.getDeclSpec().getModulePrivateSpecLoc());
     else {
       NewVD->setModulePrivate();
       if (NewTemplate)
@@ -12429,7 +12430,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
             !Context.getTargetInfo().getCXXABI().isMicrosoft()) {
           Diag(Var->getLocation(),
                diag::err_constexpr_static_mem_var_requires_init)
-            << Var->getDeclName();
+              << Var;
           Var->setInvalidDecl();
           return;
         }
@@ -12562,8 +12563,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
     // definitions with reference type.
     if (Type->isReferenceType()) {
       Diag(Var->getLocation(), diag::err_reference_var_requires_init)
-        << Var->getDeclName()
-        << SourceRange(Var->getLocation(), Var->getLocation());
+          << Var << SourceRange(Var->getLocation(), Var->getLocation());
       Var->setInvalidDecl();
       return;
     }
@@ -12696,7 +12696,7 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) {
   }
   if (Error != -1) {
     Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class)
-      << VD->getDeclName() << Error;
+        << VD << Error;
     D->setInvalidDecl();
   }
 }
@@ -13477,9 +13477,8 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
 
   if (D.getDeclSpec().isModulePrivateSpecified())
     Diag(New->getLocation(), diag::err_module_private_local)
-      << 1 << New->getDeclName()
-      << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
-      << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
+        << 1 << New << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
+        << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
 
   if (New->hasAttr<BlocksAttr>()) {
     Diag(New->getLocation(), diag::err_block_on_nonlocal);
@@ -13531,8 +13530,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(
   if (!ReturnTy->isDependentType() && ReturnTy.isPODType(Context)) {
     unsigned Size = Context.getTypeSizeInChars(ReturnTy).getQuantity();
     if (Size > LangOpts.NumLargeByValueCopy)
-      Diag(D->getLocation(), diag::warn_return_value_size)
-          << D->getDeclName() << Size;
+      Diag(D->getLocation(), diag::warn_return_value_size) << D << Size;
   }
 
   // Warn if any parameter is pass-by-value and larger than the specified
@@ -13544,7 +13542,7 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(
     unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
     if (Size > LangOpts.NumLargeByValueCopy)
       Diag(Parameter->getLocation(), diag::warn_parameter_size)
-          << Parameter->getDeclName() << Size;
+          << Parameter << Size;
   }
 }
 
@@ -13852,9 +13850,9 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
   if (getLangOpts().GNUMode && Definition->isInlineSpecified() &&
       Definition->getStorageClass() == SC_Extern)
     Diag(FD->getLocation(), diag::err_redefinition_extern_inline)
-        << FD->getDeclName() << getLangOpts().CPlusPlus;
+        << FD << getLangOpts().CPlusPlus;
   else
-    Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName();
+    Diag(FD->getLocation(), diag::err_redefinition) << FD;
 
   Diag(Definition->getLocation(), diag::note_previous_definition);
   FD->setInvalidDecl();
@@ -14909,9 +14907,10 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
   if (D.getDeclSpec().isModulePrivateSpecified()) {
     if (CurContext->isFunctionOrMethod())
       Diag(NewTD->getLocation(), diag::err_module_private_local)
-        << 2 << NewTD->getDeclName()
-        << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
-        << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc());
+          << 2 << NewTD
+          << SourceRange(D.getDeclSpec().getModulePrivateSpecLoc())
+          << FixItHint::CreateRemoval(
+                 D.getDeclSpec().getModulePrivateSpecLoc());
     else
       NewTD->setModulePrivate();
   }

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index ece93cbd6a9b..58602a4c58d4 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3643,8 +3643,8 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
       unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
                                  : S.Context.getTypeAlign(FieldType);
       S.Diag(Field->getLocation(),
-          diag::warn_transparent_union_attribute_field_size_align)
-        << isSize << Field->getDeclName() << FieldBits;
+             diag::warn_transparent_union_attribute_field_size_align)
+          << isSize << *Field << FieldBits;
       unsigned FirstBits = isSize? FirstSize : FirstAlign;
       S.Diag(FirstField->getLocation(),
              diag::note_transparent_union_first_field_size_align)

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index bb5a07e8079d..21d3bbf419a9 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -94,7 +94,7 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
         A->getSemanticSpelling() != UnusedAttr::C2x_maybe_unused) {
       const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext());
       if (DC && !DC->hasAttr<UnusedAttr>())
-        S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+        S.Diag(Loc, diag::warn_used_but_marked_unused) << D;
     }
   }
 }
@@ -5567,9 +5567,8 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD,
       return true;
     }
 
-    Diag(CallLoc,
-         diag::err_use_of_default_argument_to_function_declared_later) <<
-      FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName();
+    Diag(CallLoc, diag::err_use_of_default_argument_to_function_declared_later)
+        << FD << cast<CXXRecordDecl>(FD->getDeclContext());
     Diag(UnparsedDefaultArgLocs[Param],
          diag::note_default_argument_declared_here);
     return true;
@@ -16932,8 +16931,7 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
   if (Var->getType()->isVariablyModifiedType() && IsBlock) {
     if (Diagnose) {
       S.Diag(Loc, diag::err_ref_vm_type);
-      S.Diag(Var->getLocation(), diag::note_previous_decl)
-        << Var->getDeclName();
+      S.Diag(Var->getLocation(), diag::note_previous_decl) << Var;
     }
     return false;
   }
@@ -16945,10 +16943,8 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
         if (IsBlock)
           S.Diag(Loc, diag::err_ref_flexarray_type);
         else
-          S.Diag(Loc, diag::err_lambda_capture_flexarray_type)
-            << Var->getDeclName();
-        S.Diag(Var->getLocation(), diag::note_previous_decl)
-          << Var->getDeclName();
+          S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var;
+        S.Diag(Var->getLocation(), diag::note_previous_decl) << Var;
       }
       return false;
     }
@@ -16958,10 +16954,8 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var,
   // variables; they don't support the expected semantics.
   if (HasBlocksAttr && (IsLambda || isa<CapturedRegionScopeInfo>(CSI))) {
     if (Diagnose) {
-      S.Diag(Loc, diag::err_capture_block_variable)
-        << Var->getDeclName() << !IsLambda;
-      S.Diag(Var->getLocation(), diag::note_previous_decl)
-        << Var->getDeclName();
+      S.Diag(Loc, diag::err_capture_block_variable) << Var << !IsLambda;
+      S.Diag(Var->getLocation(), diag::note_previous_decl) << Var;
     }
     return false;
   }
@@ -16992,8 +16986,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
   if (!Invalid && !S.getLangOpts().OpenCL && CaptureType->isArrayType()) {
     if (BuildAndDiagnose) {
       S.Diag(Loc, diag::err_ref_array_type);
-      S.Diag(Var->getLocation(), diag::note_previous_decl)
-      << Var->getDeclName();
+      S.Diag(Var->getLocation(), diag::note_previous_decl) << Var;
       Invalid = true;
     } else {
       return false;
@@ -17006,8 +16999,7 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
     if (BuildAndDiagnose) {
       S.Diag(Loc, diag::err_arc_autoreleasing_capture)
         << /*block*/ 0;
-      S.Diag(Var->getLocation(), diag::note_previous_decl)
-        << Var->getDeclName();
+      S.Diag(Var->getLocation(), diag::note_previous_decl) << Var;
       Invalid = true;
     } else {
       return false;
@@ -17277,9 +17269,8 @@ bool Sema::tryCaptureVariable(
       if (BuildAndDiagnose) {
         LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI);
         if (LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None) {
-          Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
-          Diag(Var->getLocation(), diag::note_previous_decl)
-             << Var->getDeclName();
+          Diag(ExprLoc, diag::err_lambda_impcap) << Var;
+          Diag(Var->getLocation(), diag::note_previous_decl) << Var;
           Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl);
         } else
           diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC);
@@ -17353,9 +17344,8 @@ bool Sema::tryCaptureVariable(
       // No capture-default, and this is not an explicit capture
       // so cannot capture this variable.
       if (BuildAndDiagnose) {
-        Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
-        Diag(Var->getLocation(), diag::note_previous_decl)
-          << Var->getDeclName();
+        Diag(ExprLoc, diag::err_lambda_impcap) << Var;
+        Diag(Var->getLocation(), diag::note_previous_decl) << Var;
         if (cast<LambdaScopeInfo>(CSI)->Lambda)
           Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getBeginLoc(),
                diag::note_lambda_decl);
@@ -18319,7 +18309,7 @@ bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc,
       }
 
       S.Diag(Loc, diag::err_call_function_incomplete_return)
-        << CE->getSourceRange() << FD->getDeclName() << T;
+          << CE->getSourceRange() << FD << T;
       S.Diag(FD->getLocation(), diag::note_entity_declared_at)
           << FD->getDeclName();
     }

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 5b4e7a2fdafa..00563cff62cf 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -14193,12 +14193,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
       Diag(MemExpr->getBeginLoc(),
            diag::warn_call_to_pure_virtual_member_function_from_ctor_dtor)
           << MD->getDeclName() << isa<CXXDestructorDecl>(CurContext)
-          << MD->getParent()->getDeclName();
+          << MD->getParent();
 
       Diag(MD->getBeginLoc(), diag::note_previous_decl) << MD->getDeclName();
       if (getLangOpts().AppleKext)
         Diag(MemExpr->getBeginLoc(), diag::note_pure_qualified_call_kext)
-            << MD->getParent()->getDeclName() << MD->getDeclName();
+            << MD->getParent() << MD->getDeclName();
     }
   }
 

diff  --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 948c187804dc..9ca2411b33e7 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -3625,12 +3625,11 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
     if (FD->hasAttrs())
       Attrs = &FD->getAttrs();
     if (FD->isNoReturn())
-      Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
-        << FD->getDeclName();
+      Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << FD;
     if (FD->isMain() && RetValExp)
       if (isa<CXXBoolLiteralExpr>(RetValExp))
         Diag(ReturnLoc, diag::warn_main_returns_bool_literal)
-          << RetValExp->getSourceRange();
+            << RetValExp->getSourceRange();
     if (FD->hasAttr<CmseNSEntryAttr>() && RetValExp) {
       if (const auto *RT = dyn_cast<RecordType>(FnRetType.getCanonicalType())) {
         if (RT->getDecl()->isOrContainsUnion())
@@ -3701,8 +3700,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
           FunctionKind = 3;
 
         Diag(ReturnLoc, diag::err_return_init_list)
-          << CurDecl->getDeclName() << FunctionKind
-          << RetValExp->getSourceRange();
+            << CurDecl << FunctionKind << RetValExp->getSourceRange();
 
         // Drop the expression.
         RetValExp = nullptr;
@@ -3729,9 +3727,8 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
         // return of void in constructor/destructor is illegal in C++.
         if (D == diag::err_ctor_dtor_returns_void) {
           NamedDecl *CurDecl = getCurFunctionOrMethodDecl();
-          Diag(ReturnLoc, D)
-            << CurDecl->getDeclName() << isa<CXXDestructorDecl>(CurDecl)
-            << RetValExp->getSourceRange();
+          Diag(ReturnLoc, D) << CurDecl << isa<CXXDestructorDecl>(CurDecl)
+                             << RetValExp->getSourceRange();
         }
         // return (some void expression); is legal in C++.
         else if (D != diag::ext_return_has_void_expr ||
@@ -3747,8 +3744,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
             FunctionKind = 3;
 
           Diag(ReturnLoc, D)
-            << CurDecl->getDeclName() << FunctionKind
-            << RetValExp->getSourceRange();
+              << CurDecl << FunctionKind << RetValExp->getSourceRange();
         }
       }
 

diff  --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
index 0d4d34ac0e14..d92356c1ec0b 100644
--- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp
@@ -8,9 +8,10 @@ void a2 [[noreturn]] () {
 }
 
 template <typename T> void a3 [[noreturn]] () {}
-template <> void a3<int> () { return; } // expected-warning {{function 'a3' declared 'noreturn' should not return}}
+template <> void a3<int>() { return; } // expected-warning {{function 'a3<int>' declared 'noreturn' should not return}}
 
-template <typename T> void a4 [[noreturn]] () { return; } // expected-warning 2{{function 'a4' declared 'noreturn' should not return}}
+template <typename T> void a4 [[noreturn]] () { return; } // expected-warning {{function 'a4' declared 'noreturn' should not return}}
+                                                          // expected-warning at -1 {{function 'a4<long>' declared 'noreturn' should not return}}
 void a4_test() { a4<long>(); } // expected-note {{in instantiation of function template specialization 'a4<long>' requested here}}
 
 [[noreturn, noreturn]] void b() { throw 0; } // expected-error {{attribute 'noreturn' cannot appear multiple times in an attribute specifier}}

diff  --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp
index ad827fb7b314..415d634d5f98 100644
--- a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp
+++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p3.cpp
@@ -1,3 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s 
 void f(int) { } // expected-note {{previous definition is here}}
 void f(const int) { } // expected-error {{redefinition of 'f'}}
+
+template <typename T> void ft(T) {}
+template <> void ft(int) {} // expected-note {{previous definition is here}}
+template <> void ft(int) {} // expected-error {{redefinition of 'ft<int>'}}

diff  --git a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
index 01c758bef19a..7c95a3ca88eb 100644
--- a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
@@ -64,6 +64,21 @@ namespace X {
   };
 
   constexpr int operator*(const C::It &) { return 0; }
+
+  struct D {
+    D();
+    using Ty = int[2];
+    Ty *begin();
+    Ty *end();
+  };
+
+  void test_D() {
+#if __cplusplus >= 201703L
+    for (extern auto [x, y] : D()) {
+    } // expected-error at -1 {{decomposition declaration cannot be declared 'extern'}}
+      // expected-error at -2 {{loop variable '[x, y]' may not be declared 'extern'}}
+#endif
+  }
 }
 
 using X::A;

diff  --git a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
index 667152da1cbc..63f56640b1ce 100644
--- a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
+++ b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
-template<typename T> struct X; // expected-note {{'X' is incomplete}}
+template <typename T> struct X; // expected-note {{'X<X<X<int>>>' is incomplete}}
 template<int I> struct Y;
 
 X<X<int>> *x1;
@@ -14,8 +14,8 @@ typedef X<int> X_int;
 struct Z : X_int { };
 
 void f(const X<int> x) {
-  (void)reinterpret_cast<X<int>>(x); // expected-error{{reinterpret_cast from}}
-  (void)reinterpret_cast<X<X<X<int>>>>(x); // expected-error{{reinterpret_cast from}}
+  (void)reinterpret_cast<X<int>>(x);       // expected-error{{reinterpret_cast from 'const X<int>' to 'X<int>' is not allowed}}
+  (void)reinterpret_cast<X<X<X<int>>>>(x); // expected-error{{reinterpret_cast from 'const X<int>' to 'X<X<X<int>>>' is not allowed}}
 
   X<X<int>> *x1;
 }

diff  --git a/clang/test/Modules/module-private.cpp b/clang/test/Modules/module-private.cpp
index 30957865d1cd..a4b3b0fd21d3 100644
--- a/clang/test/Modules/module-private.cpp
+++ b/clang/test/Modules/module-private.cpp
@@ -1,7 +1,7 @@
 // RUN: rm -rf %t
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_left -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_right -emit-module %S/Inputs/module.map
-// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -x objective-c++ -fmodules-cache-path=%t -I %S/Inputs %s -verify
+// RUN: %clang_cc1 -std=c++17 -fmodules -fimplicit-module-maps -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_left -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -std=c++17 -fmodules -fimplicit-module-maps -x objective-c++ -fmodules-cache-path=%t -fmodule-name=module_private_right -emit-module %S/Inputs/module.map
+// RUN: %clang_cc1 -std=c++17 -fmodules -fimplicit-module-maps -x objective-c++ -fmodules-cache-path=%t -I %S/Inputs %s -verify
 // FIXME: When we have a syntax for modules in C++, use that.
 
 @import module_private_left;
@@ -79,11 +79,15 @@ __module_private__ struct public_class<T *> { }; // expected-error{{partial spec
 void local_var_private(__module_private__ int param) { // expected-error{{parameter 'param' cannot be declared __module_private__}}
   __module_private__ struct Local { int x, y; } local; //expected-error{{local variable 'local' cannot be declared __module_private__}}
 
+  __module_private__ auto [x, y] = local; // expected-error {{local variable '[x, y]' cannot be declared __module_private__}}
+
   __module_private__ struct OtherLocal { int x; }; // expected-error{{local struct cannot be declared __module_private__}}
 
   typedef __module_private__ int local_typedef; // expected-error{{typedef 'local_typedef' cannot be declared __module_private__}}
 }
 
+void param_private(__module_private__ int) {} // expected-error {{parameter '' cannot be declared __module_private}}
+
 // Check struct size
 struct LikeVisibleStruct {
   int field;

diff  --git a/clang/test/SemaCXX/array-bounds.cpp b/clang/test/SemaCXX/array-bounds.cpp
index 495ccaf71bd6..47be6c2423dc 100644
--- a/clang/test/SemaCXX/array-bounds.cpp
+++ b/clang/test/SemaCXX/array-bounds.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -std=c++14 %s
 
 int foo() {
   int x[2]; // expected-note 4 {{array 'x' declared here}}
@@ -309,3 +309,14 @@ namespace PR41087 {
     foo<int>(); // expected-note 1{{in instantiation of function template specialization}}
   };
 }
+
+namespace var_template_array {
+template <typename T> int arr[2]; // expected-note {{array 'arr<int>' declared here}}
+template <> int arr<float>[1];    // expected-note {{array 'arr<float>' declared here}}
+
+void test() {
+  arr<int>[1] = 0;   // ok
+  arr<int>[2] = 0;   // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}}
+  arr<float>[1] = 0; // expected-warning {{array index 1 is past the end of the array (which contains 1 element)}}
+}
+} // namespace var_template_array

diff  --git a/clang/test/SemaCXX/attr-unused.cpp b/clang/test/SemaCXX/attr-unused.cpp
index e3878152eca9..5bca693864e3 100644
--- a/clang/test/SemaCXX/attr-unused.cpp
+++ b/clang/test/SemaCXX/attr-unused.cpp
@@ -15,5 +15,5 @@ void f() {
   };
   (void) i;
 
-  C<int>(); // expected-warning {{'C' was marked unused but was used}}
+  C<int>(); // expected-warning {{'C<int>' was marked unused but was used}}
 }

diff  --git a/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
index fc49ec88d553..1a24c6680569 100644
--- a/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
+++ b/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
@@ -164,7 +164,7 @@ namespace constexpred {
                                                       // expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
     template<typename T> constexpr float right<float,T> = 5;  // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
     template<> static constexpr int right<int,int> = 7;
-    template<> static constexpr float right<float,int>; // expected-error {{requires an initializer}}
+    template <> static constexpr float right<float, int>; // expected-error {{declaration of constexpr static data member 'right<float, int>' requires an initializer}}
     template static constexpr int right<int,int>;     // expected-error {{expected '<' after 'template'}}
   };
 }

diff  --git a/clang/test/SemaCXX/default2.cpp b/clang/test/SemaCXX/default2.cpp
index 7651233f8636..c51d272853e7 100644
--- a/clang/test/SemaCXX/default2.cpp
+++ b/clang/test/SemaCXX/default2.cpp
@@ -119,7 +119,7 @@ class C2 {
 
 template <typename T> class C3;
 template <> class C3<int> {
-  static void g(int = f()); // expected-error {{use of default argument to function 'f' that is declared later in class 'C3'}}
+  static void g(int = f()); // expected-error {{use of default argument to function 'f' that is declared later in class 'C3<int>'}}
   static int f(int = 10); // expected-note {{default argument declared here}}
 };
 

diff  --git a/clang/test/SemaCXX/incomplete-call.cpp b/clang/test/SemaCXX/incomplete-call.cpp
index 46f470e4a881..208daa2988a6 100644
--- a/clang/test/SemaCXX/incomplete-call.cpp
+++ b/clang/test/SemaCXX/incomplete-call.cpp
@@ -40,7 +40,7 @@ void g() {
   A (B::*mfp)() = 0;
   (b.*mfp)(); // expected-error {{calling function with incomplete return type 'A'}}
 
-  ft(42); // expected-error {{calling 'ft' with incomplete return type 'A'}}
+  ft(42); // expected-error {{calling 'ft<int>' with incomplete return type 'A'}}
 }
 
 

diff  --git a/clang/test/SemaCXX/references.cpp b/clang/test/SemaCXX/references.cpp
index eaab1ae833e4..f059eb6e6460 100644
--- a/clang/test/SemaCXX/references.cpp
+++ b/clang/test/SemaCXX/references.cpp
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s 
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
 int g(int);
 
 void f() {
@@ -114,6 +115,14 @@ void test8(int& const,// expected-error{{'const' qualifier may not be applied to
   void restrict_ref(int &__restrict); // ok
 }
 
+namespace var_template {
+#if __cplusplus >= 201402L
+int i;
+template <typename> int &ref = i; // ok
+template <> int &ref<float>;      // expected-error {{declaration of reference variable 'ref<float>' requires an initializer}}
+#endif
+} // namespace var_template
+
 template<typename T> int const_param(const T) {}
 int const_ref_param = const_param<int&>(const_ref_param); // no-warning
 

diff  --git a/clang/test/SemaCXX/return-void.cpp b/clang/test/SemaCXX/return-void.cpp
index b3aa203133dc..c72fbdfae9fa 100644
--- a/clang/test/SemaCXX/return-void.cpp
+++ b/clang/test/SemaCXX/return-void.cpp
@@ -4,7 +4,7 @@ void f1() { return {1,2}; } // expected-error {{void function 'f1' must not retu
 
 template <typename T> void f2() { return {1,2}; } // expected-error {{void function 'f2' must not return a value}}
 
-template <> void f2<float>() { return {1,2}; } // expected-error {{void function 'f2' must not return a value}}
+template <> void f2<float>() { return {1, 2}; } // expected-error {{void function 'f2<float>' must not return a value}}
 
 void test_f2() {
   f2<int>();

diff  --git a/clang/test/SemaCXX/warn-func-not-needed.cpp b/clang/test/SemaCXX/warn-func-not-needed.cpp
index 5040aaad9460..cb3cae4cd6c7 100644
--- a/clang/test/SemaCXX/warn-func-not-needed.cpp
+++ b/clang/test/SemaCXX/warn-func-not-needed.cpp
@@ -11,7 +11,7 @@ void foo() {
 
 namespace test1_template {
 template <typename T> static void f() {}
-template <> void f<int>() {} // expected-warning {{function 'f' is not needed and will not be emitted}}
+template <> void f<int>() {} // expected-warning {{function 'f<int>' is not needed and will not be emitted}}
 template <typename T>
 void foo() {
   f<int>();

diff  --git a/clang/test/SemaCXX/warn-large-by-value-copy.cpp b/clang/test/SemaCXX/warn-large-by-value-copy.cpp
index 3e419ec08f07..309fdc75dbd7 100644
--- a/clang/test/SemaCXX/warn-large-by-value-copy.cpp
+++ b/clang/test/SemaCXX/warn-large-by-value-copy.cpp
@@ -16,6 +16,14 @@ S100 f100(S100 s) { return s; }
 S101 f101(S101 s) { return s; } // expected-warning {{return value of 'f101' is a large (101 bytes) pass-by-value object}} \
                                 // expected-warning {{'s' is a large (101 bytes) pass-by-value argument}}
 
+void f101_no_param_name(S101) {} // expected-warning {{'' is a large (101 bytes) pass-by-value argument}}
+
+// FIXME: Don't warn when when the return value is subject to (N)RVO.
+
+template <typename T> T foo_template(T);
+template <> S101 foo_template(S101) { return S101(); } // expected-warning {{return value of 'foo_template<rdar8548050::S101>' is a large}}
+                                                       // expected-warning at -1 {{'' is a large (101 bytes) pass-by-value argument}}
+
 typedef int Arr[200];
 void farr(Arr a) { }
 

diff  --git a/clang/test/SemaCXX/warn-member-not-needed.cpp b/clang/test/SemaCXX/warn-member-not-needed.cpp
index 95241f4f7fee..c48447719ba9 100644
--- a/clang/test/SemaCXX/warn-member-not-needed.cpp
+++ b/clang/test/SemaCXX/warn-member-not-needed.cpp
@@ -4,8 +4,8 @@ namespace {
   class A {
     void g() {} // expected-warning {{member function 'g' is not needed and will not be emitted}}
     template <typename T> void gt(T) {}
-    template <> void gt<int>(int) {} // expected-warning {{member function 'gt' is not needed and will not be emitted}}
-    template <> void gt(float) {}    // expected-warning {{member function 'gt' is not needed and will not be emitted}}
+    template <> void gt<int>(int) {} // expected-warning {{member function 'gt<int>' is not needed and will not be emitted}}
+    template <> void gt(float) {}    // expected-warning {{member function 'gt<float>' is not needed and will not be emitted}}
 
     template <typename T>
     void foo() {

diff  --git a/clang/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp b/clang/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
index 789935e3470a..9acf84c6ce8c 100644
--- a/clang/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
+++ b/clang/test/SemaCXX/warn-pure-virtual-call-from-ctor-dtor.cpp
@@ -22,8 +22,8 @@ struct C {
 };
 
 template <typename T> struct TA {
-  TA() { f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'TA'}}
-  ~TA() { f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the destructor of 'TA'}}
+  TA() { f(); }  // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'TA<float>'}}
+  ~TA() { f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the destructor of 'TA<float>'}}
 
   virtual void f() = 0; // expected-note 2{{'f' declared here}}
 };
@@ -35,8 +35,8 @@ template <> struct TA<int> {
 };
 
 template <> struct TA<long> {
-  TA() { f(); }  // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'TA'}}
-  ~TA() { f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the destructor of 'TA'}}
+  TA() { f(); }         // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'TA<long>'}}
+  ~TA() { f(); }        // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the destructor of 'TA<long>'}}
   virtual void f() = 0; // expected-note 2{{'f' declared here}}
 };
 

diff  --git a/clang/test/SemaCXX/warn-pure-virtual-kext.cpp b/clang/test/SemaCXX/warn-pure-virtual-kext.cpp
index 8431e202ad71..d23456fa4fd5 100644
--- a/clang/test/SemaCXX/warn-pure-virtual-kext.cpp
+++ b/clang/test/SemaCXX/warn-pure-virtual-kext.cpp
@@ -10,7 +10,7 @@ struct A {
 template <typename T> struct TA {
   virtual void f() = 0; // expected-note {{'f' declared here}}
 
-  TA() { TA::f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'TA'}} // expected-note {{qualified call to 'TA'::'f' is treated as a virtual call to 'f' due to -fapple-kext}}
+  TA() { TA::f(); } // expected-warning {{call to pure virtual member function 'f' has undefined behavior; overrides of 'f' in subclasses are not available in the constructor of 'TA<int>'}} // expected-note {{qualified call to 'TA<int>'::'f' is treated as a virtual call to 'f' due to -fapple-kext}}
 };
 
 struct B : TA<int> { // expected-note {{in instantiation of member function 'TA<int>::TA' requested here}}

diff  --git a/clang/test/SemaCXX/warn-unused-filescoped.cpp b/clang/test/SemaCXX/warn-unused-filescoped.cpp
index 056543d5eeb0..d53608003b16 100644
--- a/clang/test/SemaCXX/warn-unused-filescoped.cpp
+++ b/clang/test/SemaCXX/warn-unused-filescoped.cpp
@@ -67,7 +67,7 @@ struct S {
 
   template <typename T>
   void tf() {}                  // expected-warning{{unused function template 'tf'}}
-  template <> void tf<int>() {} // expected-warning{{unused function 'tf'}}
+  template <> void tf<int>() {} // expected-warning{{unused function 'tf<int>'}}
 
   struct VS {
     virtual void vm() { }
@@ -102,7 +102,7 @@ struct S2 {
 
   template <typename T, typename U> int vt = 0; // expected-warning {{unused variable template 'vt'}}
   template <typename T> int vt<T, void> = 0;
-  template <> int vt<void, void> = 0; // expected-warning {{unused variable 'vt'}}
+  template <> int vt<void, void> = 0; // expected-warning {{unused variable 'vt<void, void>'}}
 }
 
 namespace PR8841 {
@@ -132,7 +132,7 @@ namespace test4 {
 namespace rdar8733476 {
 static void foo() {}                         // expected-warning {{function 'foo' is not needed and will not be emitted}}
 template <typename T> static void foo_t() {} // expected-warning {{unused function template 'foo_t'}}
-template <> void foo_t<int>() {}             // expected-warning {{function 'foo_t' is not needed and will not be emitted}}
+template <> void foo_t<int>() {}             // expected-warning {{function 'foo_t<int>' is not needed and will not be emitted}}
 
 template <int>
 void bar() {
@@ -157,7 +157,7 @@ namespace test5 {
   namespace {
   // FIXME: Should be "unused variable template 'var_t'" instead.
   template <typename T> const double var_t = 0; // expected-warning {{unused variable 'var_t'}}
-  template <> const double var_t<int> = 0;      // expected-warning {{variable 'var_t' is not needed and will not be emitted}}
+  template <> const double var_t<int> = 0;      // expected-warning {{variable 'var_t<int>' is not needed and will not be emitted}}
   int z = sizeof(var_t<int>);                   // expected-warning {{unused variable 'z'}}
   }                                             // namespace
 }

diff  --git a/clang/test/SemaCXX/warn-variable-not-needed.cpp b/clang/test/SemaCXX/warn-variable-not-needed.cpp
index 139c2923f4ba..103be189068f 100644
--- a/clang/test/SemaCXX/warn-variable-not-needed.cpp
+++ b/clang/test/SemaCXX/warn-variable-not-needed.cpp
@@ -5,7 +5,7 @@ namespace test1 {
 
   namespace {
   template <typename T> int abc_template = 0;
-  template <> int abc_template<int> = 0; // expected-warning {{variable 'abc_template' is not needed and will not be emitted}}
+  template <> int abc_template<int> = 0; // expected-warning {{variable 'abc_template<int>' is not needed and will not be emitted}}
   }                                      // namespace
   template <typename T>
   int foo(void) {


        


More information about the cfe-commits mailing list